設(shè)計(jì)模式專欄目錄
創(chuàng)建型設(shè)計(jì)模式-單例模式/工廠模式/抽象工廠
行為型設(shè)計(jì)模式:模板設(shè)計(jì)模式/觀察者設(shè)計(jì)模式/策略設(shè)計(jì)模式
C#反射機(jī)制實(shí)現(xiàn)開閉原則的簡(jiǎn)單工廠模式
設(shè)計(jì)模式分類
設(shè)計(jì)模式可以分為三種類型:創(chuàng)建型設(shè)計(jì)模式、結(jié)構(gòu)型設(shè)計(jì)模式和行為型設(shè)計(jì)模式。
創(chuàng)建型設(shè)計(jì)模式:這些模式涉及到對(duì)象的創(chuàng)建機(jī)制,包括簡(jiǎn)單工廠模式、工廠方法模式、抽象工廠模式、單例模式、建造者模式和原型模式。
結(jié)構(gòu)型設(shè)計(jì)模式:這些模式涉及到類和對(duì)象的組合,包括適配器模式、橋接模式、組合模式、裝飾器模式、外觀模式、享元模式和代理模式。
行為型設(shè)計(jì)模式:這些模式涉及到對(duì)象之間的通信和交互,包括責(zé)任鏈模式、命令模式、解釋器模式、迭代器模式、中介者模式、備忘錄模式、觀察者模式、狀態(tài)模式、策略模式、模板方法模式和訪問者模式。
本文是對(duì)創(chuàng)建型設(shè)計(jì)模式中的單例、工廠模式的一個(gè)總結(jié)。
單例模式
定義
保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)該實(shí)例的全局訪問點(diǎn)。
示例:(懶漢模式-非線程安全)
class Singleton {
public:
static Singleton * GetInstance() {
if (_instance == nullptr) {
_instance = new Singleton();
}
return _instance;
}
private:
Singleton(){}; //構(gòu)造
~Singleton(){};
Singleton(const Singleton &) = delete; //拷? 構(gòu)造
Singleton& operator=(const Singleton&) = delete;//拷貝賦值構(gòu)造
Singleton(Singleton &&) = delete;//移動(dòng)構(gòu)造
Singleton& operator=(Singleton &&) = delete;//移動(dòng)拷貝構(gòu)造
static Singleton * _instance;
};
Singleton* Singleton::_instance = nullptr;//靜態(tài)成員需要初始化
懶漢模式與餓漢模式
直觀區(qū)別:餓漢:餓漢就是類一旦加載,就把單例初始化完成,保證getInstance的時(shí)候,單例是已經(jīng)存在了。懶漢:懶漢比較懶,只有當(dāng)調(diào)用getInstance的時(shí)候,才回去初始化這個(gè)單例。
從性能線程上的區(qū)別:
1、線程安全:餓漢式天生就是線程安全的,可以直接用于多線程而不會(huì)出現(xiàn)問題。懶漢式本身是非線程安全的。
2、資源加載和性能:餓漢式在類創(chuàng)建的同時(shí)就實(shí)例化一個(gè)靜態(tài)對(duì)象出來,不管之后會(huì)不會(huì)使用這個(gè)單例,都會(huì)占據(jù)一定的內(nèi) 存,但是相應(yīng)的,在第一次調(diào)用時(shí)速度也會(huì)更快,因?yàn)槠滟Y源已經(jīng)初始化完成。
而懶漢式顧名思義,會(huì)延遲加載,在第一次使用該單例的時(shí)候才會(huì)實(shí)例化對(duì)象出來,第一次調(diào)用時(shí)要做初始化,如果要做的工作比較多,性能上會(huì)有些延遲,之后就和餓漢式一樣了。
如果這個(gè)創(chuàng)建過程很耗時(shí),比如需要連接10000次數(shù)據(jù)庫(kù)(夸張了…??),并且這個(gè)類還并不一定會(huì)被使用,那么這個(gè)創(chuàng)建過程就是無用的。這樣的話可能懶漢模式更適合。
餓漢模式示例
#include <iostream>
using namespace std;
class Singleton
{
public:
static Singleton* instance = new Singleton();//提前實(shí)例化
static Singleton* GetInstance() {
return instance;
}
private:
Singleton(){}; //構(gòu)造
~Singleton(){};
Singleton(const Singleton &) = delete; //拷? 構(gòu)造
Singleton& operator=(const Singleton&) =
delete;//拷貝賦值構(gòu)造
Singleton(Singleton &&) = delete;//移動(dòng)構(gòu)造
Singleton& operator=(Singleton &&) =
delete;//移動(dòng)拷貝構(gòu)造
};
int main() {
Singleton* test1 = Singleton::GetInstance();
cout << test1 << endl;
Singleton* test2 = Singleton::GetInstance();
cout << test2 << endl;
return 0;
}
懶漢模式-線程安全
#include <mutex>
class Singleton { // 懶漢模式 lazy load
public:
static Singleton * GetInstance() {
//在外面加鎖會(huì)造成鎖資源浪費(fèi),,每次調(diào)用都會(huì)調(diào)用鎖。
//我們其實(shí)只需要第一次調(diào)用的時(shí)候才需要鎖,其他時(shí)候是不需要的
if (_instance == nullptr) {
std::lock_guard<std::mutex> lock(_mutex); // 雙重檢測(cè)可以避免第一次讀的時(shí)候多個(gè)線程進(jìn)入的問題。
if (_instance == nullptr) {
_instance = new Singleton();
}
}
return _instance;
}
private:
static void Destructor() {
if (nullptr != _instance) {
delete _instance;
_instance = nullptr;
}
}
Singleton(){}; //構(gòu)造
~Singleton(){};
Singleton(const Singleton &) = delete; //拷?構(gòu)造
Singleton& operator=(const Singleton&) = delete;//拷貝賦值構(gòu)造
Singleton(Singleton &&) = delete;//移動(dòng)構(gòu)造
Singleton& operator=(Singleton &&) = delete;//移動(dòng)拷貝構(gòu)造
static Singleton * _instance;
static std::mutex _mutex;
};
Singleton* Singleton::_instance = nullptr;//靜態(tài)成員需要初始化
std::mutex Singleton::_mutex; //互斥鎖初始化
- 雙重if判斷可以節(jié)約資源。不用雙重if的話需要在外層加鎖,影響效率。
為何要用到靜態(tài)成員?
當(dāng)我們正常書寫一個(gè)類,我們可以通過這個(gè)類創(chuàng)建出很多對(duì)象,這顯然是不符合單例模式規(guī)則的。無論我們是在棧上還是堆區(qū)創(chuàng)建對(duì)象,都會(huì)調(diào)用構(gòu)造函數(shù),如果將構(gòu)造函數(shù)私有化,類外就不能創(chuàng)建對(duì)象了。但是隨之帶來了新的問題,現(xiàn)在的類一個(gè)對(duì)象都創(chuàng)建不了了。
而靜態(tài)成員變量可以通過類名的方式訪問到,不一定通過創(chuàng)建對(duì)象。所以我們?cè)陬悆?nèi)public作用域下聲明一個(gè)靜態(tài)成員變量,類外是可以訪問到的。而且靜態(tài)成員變量是共享的,才符合單例設(shè)計(jì)模式。
工廠模式
開閉原則
開閉原則,在面向?qū)ο缶幊填I(lǐng)域中,規(guī)定“軟件中的對(duì)象(類,模塊,函數(shù)等等)應(yīng)該對(duì)于擴(kuò)展是開放的,但是對(duì)于修改是封閉的”,這意味著一個(gè)實(shí)體是允許在不改變它的源代碼的前提下變更它的行為。當(dāng)軟件需要變化時(shí),盡量通過擴(kuò)展軟件實(shí)體的行為來實(shí)現(xiàn)變化,而不是通過修改已有的代碼來實(shí)現(xiàn)變化。
定義
工廠模式中實(shí)例的創(chuàng)建是通過封裝了的工廠方法實(shí)現(xiàn)的,而不是常見的new操作來實(shí)現(xiàn)的。在工廠模式中,我們創(chuàng)建對(duì)象時(shí)不會(huì)對(duì)上層暴露創(chuàng)建邏輯,而是通過使用一個(gè)共同結(jié)構(gòu)來指向新創(chuàng)建的對(duì)象。
簡(jiǎn)單工廠模式
每類產(chǎn)品需要有一個(gè)虛基類,通過接收類別參數(shù)生產(chǎn)具體的產(chǎn)品。
#include <iostream>
enum ProductType
{
PRODUCT_A,
PRODUCT_B
};
// 產(chǎn)品基類
class Product
{
public:
virtual void Show() = 0;
};
// 產(chǎn)品 A
class ProductA : public Product
{
public:
void Show()
{
std::cout << "Product A." << std::endl;
}
};
// 產(chǎn)品 B
class ProductB : public Product
{
public:
void Show()
{
std::cout << "Porduct B." << std::endl;
}
};
// 工廠
class Factory
{
public:
Product* Create(int type)
{
switch(type)
{
case PRODUCT_A : return new ProductA; break;
case PRODUCT_B : return new ProductB; break;
default : break;
}
}
};
int main()
{
Factory *factory = new Factory();
factory->Create(PRODUCT_A)->Show();
factory->Create(PRODUCT_B)->Show();
return 0;
}
缺點(diǎn):簡(jiǎn)單工廠模式將所有的創(chuàng)建邏輯集中在一個(gè)工廠類中。因此需要增加新的類型產(chǎn)品的話,除了增加繼承類,還需要修改Factory類中的內(nèi)容,違背了開閉原則。
工廠方法模式
與簡(jiǎn)單工廠類相比,通過虛基工廠類來添加新的類型產(chǎn)品。
#include <iostream>
// 產(chǎn)品基類
class Product
{
public:
virtual void Show() = 0;
};
// 工廠基類
class Factory
{
public:
virtual Product* Create() = 0;
};
// 產(chǎn)品 A
class ProductA : public Product
{
public:
void Show()
{
std::cout << "Product A." << std::endl;
}
};
// 產(chǎn)品 B
class ProductB : public Product
{
public:
void Show()
{
std::cout << "Porduct B." << std::endl;
}
};
// 工廠 A
class FactoryA : public Factory
{
public:
Product* Create()
{
return new ProductA;
}
};
// 工廠 B
class FactoryB : public Factory
{
public:
Product* Create()
{
return new ProductB;
}
};
int main()
{
FactoryA *factoryA = new FactoryA();
FactoryB *factoryB = new FactoryB();
factoryA->Create()->Show();
factoryB->Create()->Show();
return 0;
}
需要新增類型產(chǎn)品時(shí),新增我們的產(chǎn)品繼承類,和工廠繼承類就行了,符合開閉原則。
缺點(diǎn):每類產(chǎn)品都需要新建一個(gè)工廠類。導(dǎo)致系統(tǒng)過大。
抽象工廠模式
相對(duì)于工廠方法模式中需要每類產(chǎn)品都需要新建一個(gè)工廠類,抽象工廠模式,是把幾類產(chǎn)品組成一個(gè)產(chǎn)品組,并在一個(gè)工廠類中去做這個(gè)產(chǎn)品組中所有產(chǎn)品的構(gòu)建動(dòng)作。
#include <iostream>
// Product A
class ProductA
{
public:
virtual void Show() = 0;
};
class ProductA1 : public ProductA
{
public:
void Show()
{
std::cout << "Product A1." << std::endl ;
}
};
class ProductA2 : public ProductA
{
public:
void Show()
{
std::cout << "Product A2." << std::endl ;
}
};
// Product B
class ProductB
{
public:
virtual void Show() = 0;
};
class ProductB1 : public ProductB
{
public:
void Show()
{
std::cout << "Product B1." << std::endl ;
}
};
class ProductB2 : public ProductB
{
public:
void Show()
{
std::cout << "Product B2." << std::endl ;
}
};
// Factory
class Factory
{
public:
virtual ProductA* CreateProductA() = 0;
virtual ProductB* CreateProductB() = 0;
};
class Factory1 : public Factory
{
public:
ProductA* CreateProductA()
{
return new ProductA1();
}
ProductB* CreateProductB()
{
return new ProductB1();
}
};
class Factory2 : public Factory
{
ProductA* CreateProductA()
{
return new ProductA2();
}
ProductB* CreateProductB()
{
return new ProductB2();
}
};
int main()
{
Factory *factoryObj1 = new Factory1();
ProductA *productObjA1 = factoryObj1->CreateProductA();
ProductB *productObjB1 = factoryObj1->CreateProductB();
productObjA1->Show();
productObjB1->Show();
Factory *factoryObj2 = new Factory2();
ProductA *productObjA2 = factoryObj2->CreateProductA();
ProductB *productObjB2 = factoryObj2->CreateProductB();
productObjA2->Show();
productObjB2->Show();
return 0;
}
缺點(diǎn):如果要改我們產(chǎn)品組的結(jié)構(gòu)的話,就需要修改我們的工廠類,這一方面就不符合開閉原則了。但在實(shí)際業(yè)務(wù)中,要避免已經(jīng)確定的產(chǎn)品組不要再改變。
工廠模式的退化過程
當(dāng)抽象工廠模式中每一個(gè)具體工廠類只創(chuàng)建一個(gè)產(chǎn)品對(duì)象,抽象工廠模式退化成工廠方法模式;當(dāng)工廠方法模式中抽象工廠與具體工廠合并,提供一個(gè)統(tǒng)一的工廠來創(chuàng)建產(chǎn)品對(duì)象,并將創(chuàng)建對(duì)象的工廠方法設(shè)計(jì)為靜態(tài)方法時(shí)(非虛類),工廠方法模式退化成簡(jiǎn)單工廠模式。文章來源:http://www.zghlxwxcb.cn/news/detail-506078.html
參考:工廠模式(C++編碼)https://www.cnblogs.com/horacle/p/15494358.html文章來源地址http://www.zghlxwxcb.cn/news/detail-506078.html
到了這里,關(guān)于結(jié)構(gòu)型設(shè)計(jì)模式-單例模式/工廠模式/抽象工廠的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!