1. 程式人生 > >結構型模式之 享元模式

結構型模式之 享元模式

控制 hit 工廠 否則 != n) 類和對象 main 實體

享元模式(Flyweight Pattern):運用共享技術有效地支持大量細粒度對象的復用。系統只使用少量的對象,而這些對象都很相似,狀態變化很小,可以實現對象的多次復用。由於享元模式要求能夠共享的對象必須是細粒度對象,因此它又稱為輕量級模式,它是一種對象結構型模式。

面向對象技術可以很好地解決一些靈活性或可擴展性問題,但在很多情況下需要在系統中增加類和對象的個數。當對象數量太多時,將導致運行代價過高,帶來性能下降等問題。

  • 享元模式正是為解決這一類問題而誕生的。享元模式通過共享技術實現相同或相似對象的重用。
  • 在享元模式中可以共享的相同內容稱為內部狀態(IntrinsicState),而那些需要外部環境來設置的不能共享的內容稱為外部狀態(Extrinsic State),由於區分了內部狀態和外部狀態,因此可以通過設置不同的外部狀態使得相同的對象可以具有一些不同的特征,而相同的內部狀態是可以共享的。
  • 在享元模式中通常會出現工廠模式,需要創建一個享元工廠來負責維護一個享元池(Flyweight Pool)用於存儲具有相同內部狀態的享元對象。
  • 在享元模式中共享的是享元對象的內部狀態,外部狀態需要通過環境來設置。在實際使用中,能夠共享的內部狀態是有限的,因此享元對象一般都設計為較小的對象,它所包含的內部狀態較少,這種對象也稱為細粒度對象。享元模式的目的就是使用共享技術來實現大量細粒度對象的復用。

主要解決:在有大量對象時,有可能會造成內存溢出,我們把其中共同的部分抽象出來,如果有相同的業務請求,直接返回在內存中已有的對象,避免重新創建。

何時使用: 1、系統中有大量對象。 2、這些對象消耗大量內存。 3、這些對象的狀態大部分可以外部化。 4、這些對象可以按照內蘊狀態分為很多組,當把外蘊對象從對象中剔除出來時,每一組對象都可以用一個對象來代替。 5、系統不依賴於這些對象身份,這些對象是不可分辨的。

如何解決:用唯一標識碼判斷,如果在內存中有,則返回這個唯一標識碼所標識的對象。

關鍵代碼:用 HashMap 存儲這些對象。

優點:大大減少對象的創建,降低系統的內存,使效率提高。

缺點:提高了系統的復雜度,需要分離出外部狀態和內部狀態,而且外部狀態具有固有化的性質,不應該隨著內部狀態的變化而變化,否則會造成系統的混亂。

使用場景: 1、系統有大量相似對象。 2、需要緩沖池的場景。

註意事項: 1、註意劃分外部狀態和內部狀態,否則可能會引起線程安全問題。 2、這些類必須有一個工廠對象加以控制。

實現

我們將創建一個 Shape 接口和實現了 Shape 接口的實體類 Circle。下一步是定義工廠類 ShapeFactory

ShapeFactory 有一個 CircleHashMap,其中鍵名為 Circle 對象的顏色。無論何時接收到請求,都會創建一個特定顏色的圓。ShapeFactory 檢查它的 HashMap 中的 circle 對象,如果找到 Circle 對象,則返回該對象,否則將創建一個存儲在 hashmap 中以備後續使用的新對象,並把該對象返回到客戶端。

FlyWeightPatternDemo,我們的演示類使用 ShapeFactory 來獲取 Shape 對象。它將向 ShapeFactory 傳遞信息(red / green / blue/ black / white),以便獲取它所需對象的顏色。

#include<iostream>
#include<memory>
#include<list>
#include<map>
#include <utility>
#include<time.h>
#include<string>
using namespace std;

//步驟一 創建一個接口
class Shape 
{
public:
    virtual void draw() {}
};
//步驟二 創建實現接口的實體類

class Circle : public Shape
{
private:
    std::string color;
    int x;
    int y;
    int radius;
public:
    Circle() { color = "red"; x = y = radius = 0; }
    Circle(string Color) { color = Color; }
    void SetX(int X) { x = X; cout << "x = " << x << endl; }
    void SetY(int Y) { y = Y; }
    void SetRadius(int Radius) { radius = Radius; }
    void draw()
    {
        std::cout << "Circle::draw() color = " << color << "  x = " << x << "  y = " << y << "   radius = " << radius << std::endl;
    }
};

//步驟 3    創建一個工廠,生成基於給定信息的實體類的對象
class ShapeFactory
{
private:
    static std::map<string, Shape*> circleMap;
public:
    static Shape* GetCircle(string color)
    {
        if (color.empty())
            return NULL;
        std::map<string, Shape*>::iterator ite = circleMap.find(color);
        if (ite != circleMap.end())
            return(ite->second);
        else 
        {
            Shape* shapetmp = new Circle;
            pair<string, Shape*> p1;
            p1 = make_pair(color, shapetmp);
            circleMap.insert(p1);
            cout << "Creating circle of color : " << color << endl;
            std::map<string, Shape*>::iterator ite2 = circleMap.find(color);
            if (ite2 != circleMap.end())
                return(ite2->second);
            return NULL;
        }
    }
    ShapeFactory() {
    }
};
map<string, Shape*>ShapeFactory::circleMap;  //靜態成員變量一定要初始化,否則出現鏈接問題


int main() 
{
    
    string colors[] =
    { "Red", "Green", "Blue", "White", "Black" };
    srand((int)time(0));
    string s1 = colors[rand() % colors->size()];
    cout << s1 << endl;
    for (int i = 0; i < 20; ++i) {
        
        Circle* circle = (Circle*)ShapeFactory::GetCircle(s1);
        circle->SetX(rand() % 100);
        circle->SetY(rand() % 100);
        circle->SetRadius(rand() % 100);
        circle->draw();
    }
    return 0;
}
//未考慮new的內存釋放問題,說明一下

結構型模式之 享元模式