設計模式——創建型模式

1.單例模式※

       整個程序有且僅有一個實例。該類負責創建自己的對象,同時確保只有一個對象被創建。

class myStaticSingleton
{
public:

	static myStaticSingleton* getInstance(){
		return &_instance;
	}

private:
	myStaticSingleton() {}

	static myStaticSingleton _instance;
};

       這裏有一個小知識點,c中的static對象在程序啓動的時候就初始化分配了內存,而c++中的static對象因爲有構造和析構函數,所以是在第一次使用的時候初始化的,並且由系統維護,在程序生命週期結束後反序析構。

//懶漢式單例

class myMutexSingleton

{

public:

static volatile myMutexSingleton* getInstance()

{

if (!_instance)

{

lock_guard<mutex> tmplock(_myMutex);

if (!_instance)

{

_instance = new myMutexSingleton();

}

}

return _instance;

}



protected:

myMutexSingleton() {};

~myMutexSingleton() {

if (_instance)

{

lock_guard<mutex> tmplock(_myMutex);

if (_instance)

{

delete _instance;

}

}

};



private:

static std::mutex _myMutex;

static volatile myMutexSingleton* _instance;

};

       這裏的_instance使用了volatile關鍵字,是因爲簡單的雙檢查鎖是不安全的,因爲new一個實例實際可以分爲了三步:分配內存,初始化對象,將_instance指向新分配內存的地址。然而有的編譯器會對這個順序重新排序,將後兩步調換了順序,這導致在_instance指向新地址後,可能另一個線程來判斷_instance是不是null,而此時_instance已經不是null了,於是返回了還未初始化的_instance。

 

2.工廠方法模式※

       定義一個用於創建對象的接口,讓子類決定實例化哪一個類,工廠方法使一個類的實例化延遲到其子類。核心工廠類不再負責產品的創建,這樣核心類成爲一個抽象工廠角色,僅負責具體工廠子類必須實現的接口,這樣進一步抽象化的好處是使的工廠方法模式可以使系統在不修改具體工廠角色的情況下引進新的產品。

  工廠方法模式是簡單工廠模式的衍生,但是工廠方法模式和簡單工廠模式又有一定的區別:簡單工廠模式的最大優點在於工廠類中包含了必要的邏輯判斷,根據客戶端的選擇條件動態實例化相關的類,對客戶端來說,去除了與具體產品的依賴。但這也是問題的所在,當我們需要添加某個對象時,我們必須要修改對應的工廠類。這可不是一個好的方法,這就等於說,我們不但對擴展開放了,對修改也開放了,這就違背了開放-封閉原則。

       工廠方法模式就是爲了解決簡單工廠模式存在的問題。首先完全遵循開放-封閉原則,實現了可擴展。其次更復雜的層次結構,可以應用於產品結果複雜的場合。但是我們仔細觀察也會發現,工廠模式實現時,客戶端需要決定實例化哪一個工廠來創建對象,選擇判斷的問題還是存在,也就是說工廠方法把簡單工廠的內部邏輯判斷移到了客戶端代碼來進行。你想要加功能,本來是修改該工廠類的,而現在是修改客戶端。

       工廠方法模式對簡單工廠模式進行了抽象。有一個抽象的Factory類,這個類將不再負責具體的產品生產,而是隻制定一些規範,具體的生產工作由其子類去完成。在這個模式中,工廠類和產品類往往可以依次對應,即一個抽象工廠對應一個抽象產品,一個具體工廠對應一個具體產品,這個具體的工廠就負責生產對應的產品。

實現:

class Car
{
public:
Car();
~Car();

virtual void Run() = 0;

private
};

class SlowCar : public Car
{
public:
void Run()
{
cout << "run slowly" << endl;
}
};

class FastCar : public Car
{
public:
void Run()
{
cout << "run fast" << endl;
}

private:
};

class CarFactory
{
public:
CarFactory();
~CarFactory();

virtual Car* CreateCar() = 0;

private:
};

class SlowCarFactory : public CarFactory
{
public:
Car *CreateCar()
{
return new SlowCar();
}

private:
};


class FastCarFactory : public CarFactory
{
public:
Car *CreateCar()
{
return new FastCar();
}

private:
};

int main()
{
CarFactory *myFac = new FastCarFactory();
Car *myCar = myFac->CreateCar();
myCar->Run();
}

 

3.抽象工廠模式※

       抽象工廠(AbstractFactory)模式的定義:是一種爲訪問類提供一個創建一組相關或相互依賴對象的接口,且訪問類無須指定所要產品的具體類就能得到同族的不同等級的產品的模式結構。
       抽象工廠模式是工廠方法模式的升級版本,工廠方法模式只生產一個等級的產品,而抽象工廠模式可生產多個等級的產品。
使用抽象工廠模式一般要滿足以下條件。

       系統中有多個產品族,每個具體工廠創建同一族但屬於不同等級結構的產品。

       系統一次只可能消費其中某一族產品,即同族的產品一起使用。
       抽象工廠模式除了具有工廠方法模式的優點外,其他主要優點如下。

       可以在類的內部對產品族中相關聯的多等級產品共同管理,而不必專門引入多個新的類來進行管理。

       當增加一個新的產品族時不需要修改原代碼,滿足開閉原則。
       其缺點是:當產品族中需要增加一個新的產品時,所有的工廠類都需要進行修改

 

class Car

{

public:

Car() {};

~Car() {};



virtual void Run() = 0;

};



class SlowCar : public Car

{

public:

void Run() {

cout << "run slowly" << endl;

}



private:

};



class FastCar : public Car

{

public:

void Run() {

cout << "run fast" << endl;

}



private:

};



class Plane

{

public:

Plane() {};

~Plane() {};



virtual void Fly() = 0;

};



class SlowPlane : public Plane

{

public:

void Fly() {

cout << "fly slowly" << endl;

}



private:

};



class FastPlane : public Plane

{

public:

void Fly() {

cout << "fly fast" << endl;

}



private:

};



class TrafficFactory

{

public:

TrafficFactory() {};

~TrafficFactory() {};



virtual Car* CreateCar() = 0;

virtual Plane* CreatePlane() = 0;

private:



};



class SlowTrafficFactory : public TrafficFactory

{

public:

Car* CreateCar() {

return new SlowCar();

}



Plane* CreatePlane()

{

return new SlowPlane();

}



private:

};



class FastTrafficFactory : public TrafficFactory

{

public:

Car* CreateCar() {

return new FastCar();

}



Plane* CreatePlane()

{

return new FastPlane();

}



private:

};



int main()

{

TrafficFactory* myFac = new SlowTrafficFactory();

Car* myCar = myFac->CreateCar();

Plane* myPlane = myFac->CreatePlane();

myPlane->Fly();

}

 

應用場景:

       抽象工廠模式最早的應用是用於創建屬於不同操作系統的視窗構件。如 java 的 AWT 中的 Button 和 Text 等構件在 Windows 和 UNIX 中的本地實現是不同的。
       抽象工廠模式通常適用於以下場景:

       當需要創建的對象是一系列相互關聯或相互依賴的產品族時,如電器工廠中的電視機、洗衣機、空調等。

       系統中有多個產品族,但每次只使用其中的某一族產品。如有人只喜歡穿某一個品牌的衣服和鞋。

       系統中提供了產品的類庫,且所有產品的接口相同,客戶端不依賴產品實例的創建細節和內部結構。

 

4.建造者模式

       在軟件的設計中,我們可能經常會遇到需要構建某個複雜的對象(比如在遊戲開發中,進行人物角色的構建),建造該對象的“過程”是穩定的(對於一個人設來都有身體,臉,髮型,手腳等),而具體建造的“細節”是不同的(每個人設的身體,臉等各有千秋)。但對於用戶來講,我纔不管這些,我只想告訴你,我現在需要某個對象(擁有某特徵的人物角色),於是你就創建一個給我就行了。

       創建者模式又叫建造者模式,是將一個複雜的對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。創建者模式隱藏了複雜對象的創建過程,它把複雜對象的創建過程加以抽象,通過子類繼承或者重載的方式,動態的創建具有複合屬性的對象。

 

5.原型模式

       通過複製一個已經存在的實例來返回新的實例,而不是新建實例。被複制的實例就是我們所稱的原型。它提供了一種快速有效的創建對象的方式。當直接創建對象的代價比較大時可以採用這種方式。

 

       這裏說到克隆就涉及到兩個知識點了:

       淺拷貝:被複制對象的所有變量都含有與原來的對象相同的值,而所有的對其他對象的引用仍然指向原對象。

       深拷貝:深拷貝把引用對象的變量指向複製過的新對象,而不是原有的被引用的對象。

       乍一看,這和c++中的拷貝構造函數很像,但仔細想想,A aa = a時,確實會執行拷貝構造函數,但是,A* aa = a,並不會執行拷貝構造函數,而且指向子類的父類指針無法構造出一個同樣的指向子類的父類對象,所以需要原型模式——實現一個clone()接口。

       相同點:原型模式和拷貝構造函數都是要產生對象的複製品。

       不同點:原型模式實現的是一個clone接口,注意是接口,也就是基於多態的clone虛函數。也就是說原型模式能夠通過基類指針來複制派生類對象。拷貝構造函數完不成這樣的任務。

        原型模式的核心是克隆,構造函數只是克隆的一個辦法而已。

 

參考:

https://blog.csdn.net/huangjh2017/article/details/78234886

http://c.biancheng.net/view/1351.html

https://blog.csdn.net/huangjh2017/article/details/78266955

https://blog.csdn.net/huangjh2017/article/details/78383389

https://blog.csdn.net/huangjh2017/article/details/78398029

https://www.cnblogs.com/jylz/p/10648439.html

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章