簡單工廠模式
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;
//抽象水果
class Fruit{
public:
virtual void shoName() = 0;
};
//蘋果類
class Apple : public Fruit{
public:
virtual void shoName(){
cout << "我是蘋果" << endl;
}
};
//香蕉類
class Banana : public Fruit{
public:
virtual void shoName(){
cout << "我是香蕉" << endl;
}
};
//鴨梨類
class Pear : public Fruit{
public:
virtual void shoName(){
cout << "我是鴨梨" << endl;
}
};
//水果工廠
class FruitFactory{
public:
static Fruit* CreateFruit(string name){
if (name.compare("apple") == 0){
return new Apple;
}
else if (name.compare("banana") == 0){
return new Banana;
}
else if (name.compare("pear") == 0){
return new Pear;
}
}
};
//測試
void test01(){
Fruit* fruit = NULL;
fruit = FruitFactory::CreateFruit("apple"); //工廠生產(chǎn)蘋果
fruit->shoName();
delete fruit;
fruit = FruitFactory::CreateFruit("banana"); //工廠生產(chǎn)香蕉
fruit->shoName();
delete fruit;
fruit = FruitFactory::CreateFruit("pear"); //工廠生產(chǎn)鴨梨
fruit->shoName();
delete fruit;
}
int main(){
test01();
return EXIT_SUCCESS;
}
簡單工廠模式的優(yōu)缺點(diǎn)及適用場景
優(yōu)點(diǎn):
(1)實(shí)現(xiàn)了對象創(chuàng)建和使用的分離椅亚。
(2)不需要記住具體類名,記住參數(shù)即可舱污,減少使用者記憶量呀舔。
缺點(diǎn):
(1)對工廠類職責(zé)過重,一旦不能工作扩灯,系統(tǒng)受到影響媚赖。
(2)增加系統(tǒng)中類的個數(shù),復(fù)雜度和理解度增加珠插。
(3)違反“開閉原則”惧磺,添加新產(chǎn)品需要修改工廠邏輯,工廠越來越復(fù)雜丧失。
適用場景:
- 工廠類負(fù)責(zé)創(chuàng)建的對象比較少豺妓,由于創(chuàng)建的對象較少,不會造成工廠方法中的業(yè)務(wù)邏輯太過復(fù)雜布讹。
- 客戶端只知道傳入工廠類的參數(shù)琳拭,對于如何創(chuàng)建對象并不關(guān)心。
工廠方法模式
工廠方法(Factory Method)模式的意義是定義一個創(chuàng)建產(chǎn)品對象的工廠接口描验,將實(shí)際創(chuàng)建工作推遲到子類當(dāng)中白嘁。核心工廠類不再負(fù)責(zé)產(chǎn)品的創(chuàng)建,這樣核心類成為一個抽象工廠角色膘流,僅負(fù)責(zé)具體工廠子類必須實(shí)現(xiàn)的接口絮缅,這樣進(jìn)一步抽象化的好處是使得工廠方法模式可以使系統(tǒng)在不修改具體工廠角色的情況下引進(jìn)新的產(chǎn)品。
工廠方法模式是簡單工廠模式的衍生呼股,解決了許多簡單工廠模式的問題耕魄。
首先完全實(shí)現(xiàn)‘開閉原則’,實(shí)現(xiàn)了可擴(kuò)展彭谁。
工廠方法模式中的角色與職責(zé):
抽象工廠(Abstract Factory)角色:工廠方法模式的核心吸奴,任何工廠類都必須實(shí)現(xiàn)這個接口。
工廠(Concrete Factory)角色:具體工廠類是抽象工廠的一個實(shí)現(xiàn),負(fù)責(zé)實(shí)例化產(chǎn)品對象则奥。
抽象產(chǎn)品(Abstract Product)角色:工廠方法模式所創(chuàng)建的所有對象的父類考润,它負(fù)責(zé)描述所有實(shí)例所共有的公共接口。
具體產(chǎn)品(Concrete Product)角色:工廠方法模式所創(chuàng)建的具體實(shí)例對象读处。
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
//抽象水果
class AbstractFruit{
public:
virtual void showName() = 0;
};
/* 具體水果 start */
//蘋果
class Apple : public AbstractFruit{
public:
virtual void showName(){
cout << "我是蘋果" << endl;
}
};
//香蕉
class Banana : public AbstractFruit{
public:
virtual void showName(){
cout << "我是香蕉" << endl;
}
};
//鴨梨
class Pear : public AbstractFruit{
public:
virtual void showName(){
cout << "我是鴨梨" << endl;
}
};
/* 具體水果 end */
//抽象工廠
class AbstractFactory{
public:
virtual AbstractFruit* CreateFruit() = 0;
};
/* 具體工廠類 start */
//蘋果工廠
class AppleFactory : public AbstractFactory{
public:
virtual AbstractFruit* CreateFruit(){
return new Apple;
}
};
//香蕉工廠
class BananaFactory : public AbstractFactory{
public:
virtual AbstractFruit* CreateFruit(){
return new Banana;
}
};
//鴨梨工廠
class PearFactory : public AbstractFactory{
public:
virtual AbstractFruit* CreateFruit(){
return new Pear;
}
};
/* 具體工廠類 end */
//測試
void test01(){
AbstractFactory* factory = NULL;
AbstractFruit* fruit = NULL;
factory = new AppleFactory; //創(chuàng)建蘋果工廠
fruit = factory->CreateFruit(); //蘋果工廠生產(chǎn)蘋果
fruit->showName();
factory = new BananaFactory; //創(chuàng)建香蕉工廠
fruit = factory->CreateFruit(); //香蕉工廠生產(chǎn)蘋果
fruit->showName();
factory = new PearFactory; //創(chuàng)建鴨梨工廠
fruit = factory->CreateFruit(); //鴨梨工廠生產(chǎn)蘋果
fruit->showName();
}
int main(){
test01();
return EXIT_SUCCESS;
}
工廠方法模式的優(yōu)缺點(diǎn)及適用場景
優(yōu)點(diǎn):
(1)不需要記住具體類名糊治,甚至連具體參數(shù)都不用記憶。
(2)實(shí)現(xiàn)了對象創(chuàng)建和使用的分離罚舱。
(3)系統(tǒng)的可擴(kuò)展性也就變得非常好井辜,無需修改接口和原類。
缺點(diǎn):
(1)增加系統(tǒng)中類的個數(shù)馆匿,復(fù)雜度和理解度增加抑胎。
(2)增加了系統(tǒng)的抽象性和理解難度。
適用場景:
- 客戶端不知道它所需要的對象的類渐北。
- 抽象工廠類通過其子類來指定創(chuàng)建哪個對象阿逃。
抽象工廠模式
工廠方法模式通過引入工廠等級結(jié)構(gòu),解決了簡單工廠模式中工廠類職責(zé)太重的問題赃蛛,但由于工廠方法模式中的每個工廠只生產(chǎn)一類產(chǎn)品恃锉,可能會導(dǎo)致系統(tǒng)中存在大量的工廠類,勢必會增加系統(tǒng)的開銷呕臂。此時破托,我們可以考慮將一些相關(guān)的產(chǎn)品組成一個“產(chǎn)品族,由同一個工廠來統(tǒng)一生產(chǎn)歧蒋,這就是我們本文將要學(xué)習(xí)的抽象工廠模式的基本思想土砂。
模式中的角色和職責(zé):
抽象工廠(Abstract Factory)角色:它聲明了一組用于創(chuàng)建一族產(chǎn)品的方法,每一個方法對應(yīng)一種產(chǎn)品谜洽。
具體工廠(Concrete Factory)角色:它實(shí)現(xiàn)了在抽象工廠中聲明的創(chuàng)建產(chǎn)品的方法萝映,生成一組具體產(chǎn)品,這些產(chǎn)品構(gòu)成了一個產(chǎn)品族阐虚,每一個產(chǎn)品都位于某個產(chǎn)品等級結(jié)構(gòu)中序臂。
抽象產(chǎn)品(Abstract Product)角色:它為每種產(chǎn)品聲明接口,在抽象產(chǎn)品中聲明了產(chǎn)品所具有的業(yè)務(wù)方法实束。
具體產(chǎn)品(Concrete Product)角色:它定義具體工廠生產(chǎn)的具體產(chǎn)品對象奥秆,實(shí)現(xiàn)抽象產(chǎn)品接口中聲明的業(yè)務(wù)方法。
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
//抽象蘋果類
class AbstractApple{
public:
virtual void showName() = 0;
};
//抽象香蕉
class AbstractBanana{
public:
virtual void showName() = 0;
};
//抽象鴨梨
class AbstractPear{
public:
virtual void showName() = 0;
};
//中國蘋果
class ChineseApple : public AbstractApple{
public:
virtual void showName(){
cout << "中國蘋果" << endl;
}
};
//美國蘋果
class AmericanApple : public AbstractApple{
public:
virtual void showName(){
cout << "美國蘋果" << endl;
}
};
//日本蘋果
class JapaneseApple : public AbstractApple{
public:
virtual void showName(){
cout << "日本蘋果" << endl;
}
};
//中國香蕉
class ChineseBanana : public AbstractBanana{
public:
virtual void showName(){
cout << "中國香蕉" << endl;
}
};
//美國香蕉
class AmericanBanana : public AbstractBanana{
public:
virtual void showName(){
cout << "美國香蕉" << endl;
}
};
//日本香蕉
class JapaneseBanana : public AbstractBanana{
public:
virtual void showName(){
cout << "日本香蕉" << endl;
}
};
//中國鴨梨
class ChinesePear : public AbstractPear{
public:
virtual void showName(){
cout << "中國鴨梨" << endl;
}
};
//美國鴨梨
class AmericanPear : public AbstractPear{
public:
virtual void showName(){
cout << "美國鴨梨" << endl;
}
};
//日本鴨梨
class JapanesePear : public AbstractPear{
public:
virtual void showName(){
cout << "日本鴨梨" << endl;
}
};
//抽象工廠
class AbstractFactory{
public:
virtual AbstractApple* CreateApple() = 0;
virtual AbstractBanana* CreateBanana() = 0;
virtual AbstractPear* CreatePear() = 0;
};
//中國工廠
class ChineseFactory : public AbstractFactory{
public:
virtual AbstractApple* CreateApple(){
return new ChineseApple;
}
virtual AbstractBanana* CreateBanana(){
return new ChineseBanana;
}
virtual AbstractPear* CreatePear(){
return new ChinesePear;
}
};
//美國工廠
class AmericanFactory : public AbstractFactory{
public:
virtual AbstractApple* CreateApple(){
return new AmericanApple;
}
virtual AbstractBanana* CreateBanana(){
return new AmericanBanana;
}
virtual AbstractPear* CreatePear(){
return new AmericanPear;
}
};
//美國工廠
class JapaneseFactory : public AbstractFactory{
public:
virtual AbstractApple* CreateApple(){
return new JapaneseApple;
}
virtual AbstractBanana* CreateBanana(){
return new JapaneseBanana;
}
virtual AbstractPear* CreatePear(){
return new JapanesePear;
}
};
void test01(){
AbstractFactory* factory = NULL;
AbstractApple* apple = NULL;
AbstractBanana* banana = NULL;
AbstractPear* pear = NULL;
factory = new ChineseFactory; //創(chuàng)建中國工廠
apple = factory->CreateApple();
banana = factory->CreateBanana();
pear = factory->CreatePear();
apple->showName();
banana->showName();
pear->showName();
delete pear;
delete banana;
delete apple;
delete factory;
factory = new AmericanFactory; //創(chuàng)建美國工廠
apple = factory->CreateApple();
banana = factory->CreateBanana();
pear = factory->CreatePear();
apple->showName();
banana->showName();
pear->showName();
delete pear;
delete banana;
delete apple;
delete factory;
factory = new JapaneseFactory; //創(chuàng)建日本工廠
apple = factory->CreateApple();
banana = factory->CreateBanana();
pear = factory->CreatePear();
apple->showName();
banana->showName();
pear->showName();
delete pear;
delete banana;
delete apple;
delete factory;
}
int main(){
test01();
return EXIT_SUCCESS;
}
抽象工廠模式的優(yōu)缺點(diǎn)及適用場景
優(yōu)點(diǎn):
(1)擁有工廠方法模式的優(yōu)點(diǎn)
(2)當(dāng)一個產(chǎn)品族中的多個對象被設(shè)計成一起工作時咸灿,它能夠保證客戶端始終只使用同一個產(chǎn)品族中的對象构订。
(3)增加新的產(chǎn)品族很方便,無須修改已有系統(tǒng)避矢,符合“開閉原則”鲫咽。
缺點(diǎn):
增加新的產(chǎn)品等級結(jié)構(gòu)麻煩签赃,需要對原有系統(tǒng)進(jìn)行較大的修改谷异,甚至需要修改抽象層代碼分尸,這顯然會帶來較大的不便,違背了“開閉原則”歹嘹。
適用場景:
(1) 系統(tǒng)中有多于一個的產(chǎn)品族箩绍。而每次只使用其中某一產(chǎn)品族〕呱希可以通過配置文件等方式來使得用戶可以動態(tài)改變產(chǎn)品族材蛛,也可以很方便地增加新的產(chǎn)品族。
(2) 產(chǎn)品等級結(jié)構(gòu)穩(wěn)定怎抛。設(shè)計完成之后卑吭,不會向系統(tǒng)中增加新的產(chǎn)品等級結(jié)構(gòu)或者刪除已有的產(chǎn)品等級結(jié)構(gòu)。
單例模式
單例模式是一種常用的軟件設(shè)計模式马绝。在它的核心結(jié)構(gòu)中只包含一個被稱為單例的特殊類豆赏。通過單例模式可以保證系統(tǒng)中一個類只有一個實(shí)例而且該實(shí)例易于外界訪問,從而方便對實(shí)例個數(shù)的控制并節(jié)約系統(tǒng)資源富稻。如果希望在系統(tǒng)中某個類的對象只能存在一個掷邦,單例模式是最好的解決方案。
Singleton(單例):在單例類的內(nèi)部實(shí)現(xiàn)只生成一個實(shí)例椭赋,同時它提供一個靜態(tài)的getInstance()工廠方法抚岗,讓客戶可以訪問它的唯一實(shí)例;為了防止在外部對其實(shí)例化哪怔,將其構(gòu)造函數(shù)設(shè)計為私有宣蔚;在單例類內(nèi)部定義了一個Singleton類型的靜態(tài)對象,作為外部共享的唯一實(shí)例认境。
(重點(diǎn))
如何構(gòu)建單例:
一是單例模式的類只提供私有的構(gòu)造函數(shù)胚委,
二是類定義中含有一個該類的靜態(tài)私有對象,
三是該類提供了一個靜態(tài)的公有的函數(shù)用于創(chuàng)建或獲取它本身的靜態(tài)私有對象元暴。
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
/* 懶漢式 */
class Chairman_lazy{
private:
Chairman_lazy(){}
public:
static Chairman_lazy* getInstance(){
if (s_singleton == NULL){
s_singleton = new Chairman_lazy;
}
return s_singleton;
}
private:
static Chairman_lazy* s_singleton;
};
Chairman_lazy* Chairman_lazy::s_singleton = NULL;
void test01(){
Chairman_lazy* chairman1 = Chairman_lazy::getInstance();
Chairman_lazy* chairman2 = Chairman_lazy::getInstance();
if (chairman1 == chairman2){
cout << "指向同一個對象!" << endl;
}
else{
cout << "指向不是同一個對象!" << endl;
}
}
/* 餓漢式 */
class Chairman_hangry{
private:
Chairman_hangry(){}
public:
static Chairman_hangry* getInstance(){
return s_singleton;
}
private:
static Chairman_hangry* s_singleton;
};
//初始化
Chairman_hangry* Chairman_hangry::s_singleton = new Chairman_hangry;
void test02(){
Chairman_hangry* chairman1 = Chairman_hangry::getInstance();
Chairman_hangry* chairman2 = Chairman_hangry::getInstance();
if (chairman1 == chairman2){
cout << "指向同一個對象!" << endl;
}
else{
cout << "指向不是同一個對象!" << endl;
}
}
int main(){
//test01();
test02();
return EXIT_SUCCESS;
}
單例模式遇到多線程時
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<Windows.h>
using namespace std;
/* 懶漢式 */
class Chairman_lazy{
private:
Chairman_lazy(){}
public:
static Chairman_lazy* getInstance(){
if (s_singleton == NULL){
//Sleep(1000); //等到1000秒
s_singleton = new Chairman_lazy;
}
return s_singleton;
}
private:
static Chairman_lazy* s_singleton;
};
Chairman_lazy* Chairman_lazy::s_singleton = NULL;
/* 餓漢式 */
class Chairman_hangry{
private:
Chairman_hangry(){}
public:
static Chairman_hangry* getInstance(){
return s_singleton;
}
private:
static Chairman_hangry* s_singleton;
};
//初始化
Chairman_hangry* Chairman_hangry::s_singleton = new Chairman_hangry;
DWORD WINAPI MyThread_hangry(LPVOID lpThreadParameter){
Chairman_hangry* chairman = Chairman_hangry::getInstance();
cout << "單例對象地址:" << (int*)chairman << endl;
return 0;
}
//餓漢式單例碰到多線程測試
void test01(){
HANDLE handler[10];
for (int i = 0; i < 10;i++){
handler[i] = CreateThread(NULL, NULL, MyThread_hangry, NULL, NULL, NULL);
}
}
DWORD WINAPI MyThread_lazy(LPVOID lpThreadParameter){
Chairman_lazy* chairman = Chairman_lazy::getInstance();
cout << "單例對象地址:" << (int*)chairman << endl;
return 0;
}
//懶漢式單例碰到多線程
void test02(){
HANDLE handler[10];
for (int i = 0; i < 10; i++){
handler[i] = CreateThread(NULL, NULL, MyThread_lazy, NULL, NULL, NULL);
}
}
int main(){
test01();
test02();
return EXIT_SUCCESS;
}
運(yùn)行結(jié)果:
餓漢式單例模式的單例對象地址是全部一致的
懶漢式單例模式的單例對象地址都不一致
由上面的結(jié)果可知篷扩,懶漢式單例模式下的多線程是不安全的。
原因:懶漢式的getInstance語句是這樣的:
static Chairman_lazy* getInstance(){
if (s_singleton == NULL){
//Sleep(1000); //等到1000秒
s_singleton = new Chairman_lazy;
}
return s_singleton;
}
假如多個Chairman_lazy* Chairman_lazy::s_singleton = NULL;語句
因?yàn)槎嗑€程下這些語句會同時執(zhí)行茉盏,那么會同時new很多實(shí)例鉴未,所以不安全
相反,餓漢模式只會在全局new一個實(shí)例鸠姨,getInstance語句是直接返回指針铜秆,所以安全。
//線程安全的懶漢模式
class singleton
{
protected:
singleton()
{
pthread_mutex_init(&mutex);
}
private:
static singleton* p;
public:
static pthread_mutex_t mutex;
static singleton* initance();
};
pthread_mutex_t singleton::mutex;
singleton* singleton::p = NULL;
singleton* singleton::initance()
{
if (p == NULL)
{
pthread_mutex_lock(&mutex);
if (p == NULL)
p = new singleton();
pthread_mutex_unlock(&mutex);
}
return p;
}
單例模式的優(yōu)缺點(diǎn)及適用場景
優(yōu)點(diǎn):
(1)單例模式提供了對唯一實(shí)例的受控訪問讶迁。
(2)節(jié)約系統(tǒng)資源连茧。由于在系統(tǒng)內(nèi)存中只存在一個對象。
缺點(diǎn):
(1) 擴(kuò)展略難。單例模式中沒有抽象層啸驯。
(2) 單例類的職責(zé)過重客扎。
適用場景:
(1) 系統(tǒng)只需要一個實(shí)例對象,如系統(tǒng)要求提供一個唯一的序列號生成器或資源管理器罚斗,或者需要考慮資源消耗太大而只允許創(chuàng)建一個對象徙鱼。
(2) 客戶調(diào)用類的單個實(shí)例只允許使用一個公共訪問點(diǎn),除了該公共訪問點(diǎn)针姿,不能通過其他途徑訪問該實(shí)例袱吆。
關(guān)于單例對象內(nèi)存的釋放問題
一般一個單例對象占用的內(nèi)存很少,就算不釋放內(nèi)存也沒關(guān)系
如果真的想是釋放距淫,可以用嵌套類來實(shí)現(xiàn)
最重要的一點(diǎn)绞绒,之所以不寫析構(gòu)函數(shù),是因?yàn)閱卫J降膶?shí)例是存儲在堆中榕暇,不會自動析構(gòu)蓬衡,所以需要借助內(nèi)嵌類delete觸發(fā)。
class Chairman_hangry{
private:
Chairman_hangry(){}
~Chairman_hangry(){}
public:
static Chairman_hangry* getInstance(){
return s_singleton;
}
class Garbo{
public:
~Garbo(){
if(s_singleton!=NULL)
delete s_singleton;
}
};
private:
static Chairman_hangry* s_singleton;
static Garbo garbo;
};
Chairman_hangry* Chairman_hangry::s_singleton=new Chairman_hangry;
Chairman_hangry::Garbo Chairman_hangry::garbo; //這句很重要