學(xué)習(xí)設(shè)計模式(2)

創(chuàng)建型模式

抽象工廠模式(abstract facroty)

3.1模式動機
  • 在工廠方法模式中具體工廠負責(zé)生產(chǎn)具體的產(chǎn)品,每一個具體工廠對應(yīng)一種具體產(chǎn)品,工廠方法也具有唯一性,一般情況下,一個具體工廠中只有一個工廠方法或者一組重載的工廠方法。但是有時候我們需要一個工廠可以提供多個產(chǎn)品對象,而不是單一的產(chǎn)品對象。兩個概念
  • 產(chǎn)品等級結(jié)構(gòu):產(chǎn)品等級結(jié)構(gòu)即產(chǎn)品的繼承結(jié)構(gòu),如一個抽象類是電視機,其子類有海爾電視機、海信電視機、TCL電視機,則抽象電視機與具體品牌的電視機之間構(gòu)成了一個產(chǎn)品等級結(jié)構(gòu),抽象電視機是父類,而具體品牌的電視機是其子類。
  • 產(chǎn)品族 :在抽象工廠模式中,產(chǎn)品族是指由同一個工廠生產(chǎn)的,位于不同產(chǎn)品等級結(jié)構(gòu)中的一組產(chǎn)品,如海爾電器工廠生產(chǎn)的海爾電視機、海爾電冰箱,海爾電視機位于電視機產(chǎn)品等級結(jié)構(gòu)中,海爾電冰箱位于電冰箱產(chǎn)品等級結(jié)構(gòu)中。
  • 當(dāng)系統(tǒng)所提供的工廠所需生產(chǎn)的具體產(chǎn)品并不是一個簡單的對象,而是多個位于不同產(chǎn)品等級結(jié)構(gòu)中屬于不同類型的具體產(chǎn)品時需要使用抽象工廠模式。
  • 抽象工廠模式是所有形式的工廠模式中最為抽象和最具一般性的一種形態(tài)
  • 抽象工廠模式與工廠方法模式最大的區(qū)別在于,工廠方法模式針對的是一個產(chǎn)品等級結(jié)構(gòu),而抽象工廠模式則需要面對多個產(chǎn)品等級結(jié)構(gòu),一個工廠等級結(jié)構(gòu)可以負責(zé)多個不同產(chǎn)品等級結(jié)構(gòu)中的產(chǎn)品對象的創(chuàng)建 。當(dāng)一個工廠等級結(jié)構(gòu)可以創(chuàng)建出分屬于不同產(chǎn)品等級結(jié)構(gòu)的一個產(chǎn)品族中的所有對象時,抽象工廠模式比工廠方法模式更為簡單、有效率。
3.2模式定義
  • 抽象工廠模式(Abstract Factory Pattern):提供一個創(chuàng)建一系列相關(guān)或相互依賴對象的接口,而無須指定它們具體的類。抽象工廠模式又稱為Kit模式,屬于對象創(chuàng)建型模式。
3.3模式結(jié)構(gòu)

抽象工廠模式包含如下角色:

  • AbstractFactory:抽象工廠
  • ConcreteFactory:具體工廠
  • AbstractProduct:抽象產(chǎn)品
  • Product:具體產(chǎn)品
AbatractFactory.jpg
3.4代碼分析
#include <iostream>
#include "AbstractFactory.h"
#include "AbstractProductA.h"
#include "AbstractProductB.h"
#include "ConcreteFactory1.h"
#include "ConcreteFactory2.h"
using namespace std;

int main(int argc, char *argv[])
{
    AbstractFactory * fc = new ConcreteFactory1();
    AbstractProductA * pa =  fc->createProductA();
    AbstractProductB * pb = fc->createProductB();
    pa->use();
    pb->eat();
    
    AbstractFactory * fc2 = new ConcreteFactory2();
    AbstractProductA * pa2 =  fc2->createProductA();
    AbstractProductB * pb2 = fc2->createProductB();
    pa2->use();
    pb2->eat(); ```

include "ConcreteFactory1.h"

include "ProductA1.h"

include "ProductB1.h"

AbstractProductA * ConcreteFactory1::createProductA(){
return new ProductA1();
}

AbstractProductB * ConcreteFactory1::createProductB(){
return new ProductB1();
}

include "ProductA1.h"

include <iostream>

using namespace std;
void ProductA1::use(){
cout << "use Product A1" << endl;
}

######3.5優(yōu)點
- 抽象工廠模式隔離了具體類的生成,使得客戶并不需要知道什么被創(chuàng)建。由于這種隔離,更換一個具體工廠就變得相對容易。所有的具體工廠都實現(xiàn)了抽象工廠中定義的那些公共接口,因此只需改變具體工廠的實例,就可以在某種程度上改變整個軟件系統(tǒng)的行為。另外,應(yīng)用抽象工廠模式可以實現(xiàn)高內(nèi)聚低耦合的設(shè)計目的,因此抽象工廠模式得到了廣泛的應(yīng)用。
- 當(dāng)一個產(chǎn)品族中的多個對象被設(shè)計成一起工作時,它能夠保證客戶端始終只使用同一個產(chǎn)品族中的對象。這對一些需要根據(jù)當(dāng)前環(huán)境來決定其行為的軟件系統(tǒng)來說,是一種非常實用的設(shè)計模式。
- 增加新的具體工廠和產(chǎn)品族很方便,無須修改已有系統(tǒng),符合“開閉原則”。

######3.6缺點
在以下情況下可以使用抽象工廠模式:

- 一個系統(tǒng)不應(yīng)當(dāng)依賴于產(chǎn)品類實例如何被創(chuàng)建、組合和表達的細節(jié),這對于所有類型的工廠模式都是重要的。
- 系統(tǒng)中有多于一個的產(chǎn)品族,而每次只使用其中某一產(chǎn)品族。
- 屬于同一個產(chǎn)品族的產(chǎn)品將在一起使用,這一約束必須在系統(tǒng)的設(shè)計中體現(xiàn)出來。
- 系統(tǒng)提供一個產(chǎn)品類的庫,所有的產(chǎn)品以同樣的接口出現(xiàn),從而使客戶端不依賴于具體實現(xiàn)。

######3.7模式應(yīng)用

在很多軟件系統(tǒng)中需要更換界面主題,要求界面中的按鈕、文本框、背景色等一起發(fā)生改變時,可以使用抽象工廠模式進行設(shè)計。

######3.8模式擴展

開閉原則”的傾斜性
- “開閉原則”要求系統(tǒng)對擴展開放,對修改封閉,通過擴展達到增強其功能的目的。對于涉及到多個產(chǎn)品族與多個產(chǎn)品等級結(jié)構(gòu)的系統(tǒng),其功能增強包括兩方面:
 - 增加產(chǎn)品族:對于增加新的產(chǎn)品族,工廠方法模式很好的支持了“開閉原則”,對于新增加的產(chǎn)品族,只需要對應(yīng)增加一個新的具體工廠即可,對已有代碼無須做任何修改。
 - 增加新的產(chǎn)品等級結(jié)構(gòu):對于增加新的產(chǎn)品等級結(jié)構(gòu),需要修改所有的工廠角色,包括抽象工廠類,在所有的工廠類中都需要增加生產(chǎn)新產(chǎn)品的方法,不能很好地支持“開閉原則”。

- 抽象工廠模式的這種性質(zhì)稱為“開閉原則”的傾斜性,抽象工廠模式以一種傾斜的方式支持增加新的產(chǎn)品,它為新產(chǎn)品族的增加提供方便,但不能為新的產(chǎn)品等級結(jié)構(gòu)的增加提供這樣的方便。

工廠模式的退化
- 當(dāng)抽象工廠模式中每一個具體工廠類只創(chuàng)建一個產(chǎn)品對象,也就是只存在一個產(chǎn)品等級結(jié)構(gòu)時,抽象工廠模式退化成工廠方法模式;當(dāng)工廠方法模式中抽象工廠與具體工廠合并,提供一個統(tǒng)一的工廠來創(chuàng)建產(chǎn)品對象,并將創(chuàng)建對象的工廠方法設(shè)計為靜態(tài)方法時,工廠方法模式退化成簡單工廠模式。

######3.9 總結(jié)
- 抽象工廠模式提供一個創(chuàng)建一系列相關(guān)或相互依賴對象的接口,而無須指定它們具體的類。抽象工廠模式又稱為Kit模式,屬于對象創(chuàng)建型模式。
- 抽象工廠模式包含四個角色:抽象工廠用于聲明生成抽象產(chǎn)品的方法;具體工廠實現(xiàn)了抽象工廠聲明的生成抽象產(chǎn)品的方法,生成一組具體產(chǎn)品,這些產(chǎn)品構(gòu)成了一個產(chǎn)品族,每一個產(chǎn)品都位于某個產(chǎn)品等級結(jié)構(gòu)中;抽象產(chǎn)品為每種產(chǎn)品聲明接口,在抽象產(chǎn)品中定義了產(chǎn)品的抽象業(yè)務(wù)方法;具體產(chǎn)品定義具體工廠生產(chǎn)的具體產(chǎn)品對象,實現(xiàn)抽象產(chǎn)品接口中定義的業(yè)務(wù)方法。
- 抽象工廠模式是所有形式的工廠模式中最為抽象和最具一般性的一種形態(tài)。抽象工廠模式與工廠方法模式最大的區(qū)別在于,工廠方法模式針對的是一個產(chǎn)品等級結(jié)構(gòu),而抽象工廠模式則需要面對多個產(chǎn)品等級結(jié)構(gòu)。
- 抽象工廠模式的主要優(yōu)點是隔離了具體類的生成,使得客戶并不需要知道什么被創(chuàng)建,而且每次可以通過具體工廠類創(chuàng)建一個產(chǎn)品族中的多個對象,增加或者替換產(chǎn)品族比較方便,增加新的具體工廠和產(chǎn)品族很方便;主要缺點在于增加新的產(chǎn)品等級結(jié)構(gòu)很復(fù)雜,需要修改抽象工廠和所有的具體工廠類,對“開閉原則”的支持呈現(xiàn)傾斜性。
- 抽象工廠模式適用情況包括:一個系統(tǒng)不應(yīng)當(dāng)依賴于產(chǎn)品類實例如何被創(chuàng)建、組合和表達的細節(jié);系統(tǒng)中有多于一個的產(chǎn)品族,而每次只使用其中某一產(chǎn)品族;屬于同一個產(chǎn)品族的產(chǎn)品將在一起使用;系統(tǒng)提供一個產(chǎn)品類的庫,所有的產(chǎn)品以同樣的接口出現(xiàn),從而使客戶端不依賴于具體實現(xiàn)。

##建造者模式

######4.1模式動機

無論是在現(xiàn)實世界中還是在軟件系統(tǒng)中,都存在一些復(fù)雜的對象,它們擁有多個組成部分,如汽車,它包括車輪、方向盤、發(fā)送機等各種部件。而對于大多數(shù)用戶而言,無須知道這些部件的裝配細節(jié),也幾乎不會使用單獨某個部件,而是使用一輛完整的汽車,可以通過建造者模式對其進行設(shè)計與描述,建造者模式可以將部件和其組裝過程分開,一步一步創(chuàng)建一個復(fù)雜的對象。用戶只需要指定復(fù)雜對象的類型就可以得到該對象,而無須知道其內(nèi)部的具體構(gòu)造細節(jié)。
在軟件開發(fā)中,也存在大量類似汽車一樣的復(fù)雜對象,它們擁有一系列成員屬性,這些成員屬性中有些是引用類型的成員對象。而且在這些復(fù)雜對象中,還可能存在一些限制條件,如某些屬性沒有賦值則復(fù)雜對象不能作為一個完整的產(chǎn)品使用;有些屬性的賦值必須按照某個順序,一個屬性沒有賦值之前,另一個屬性可能無法賦值等。
復(fù)雜對象相當(dāng)于一輛有待建造的汽車,而對象的屬性相當(dāng)于汽車的部件,建造產(chǎn)品的過程就相當(dāng)于組合部件的過程。由于組合部件的過程很復(fù)雜,因此,這些部件的組合過程往往被“外部化”到一個稱作建造者的對象里,建造者返還給客戶端的是一個已經(jīng)建造完畢的完整產(chǎn)品對象,而用戶無須關(guān)心該對象所包含的屬性以及它們的組裝方式,這就是建造者模式的模式動機。
######4.2模式定義
造者模式(Builder Pattern):將一個復(fù)雜對象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。
建造者模式是一步一步創(chuàng)建一個復(fù)雜的對象,它允許用戶只通過指定復(fù)雜對象的類型和內(nèi)容就可以構(gòu)建它們,用戶不需要知道內(nèi)部的具體構(gòu)建細節(jié)。建造者模式屬于對象創(chuàng)建型模式。根據(jù)中文翻譯的不同,建造者模式又可以稱為生成器模式。

######4.3模式結(jié)構(gòu)
- Builder:抽象建造者
- ConcreteBuilder:具體建造者
- Director:指揮者
- Product:產(chǎn)品角色

![Builder.jpg](http://upload-images.jianshu.io/upload_images/4979809-2f2dc1764d6f3108.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

######4.4代碼

include "ConcreteBuilder.h"

ConcreteBuilder::ConcreteBuilder(){

}
ConcreteBuilder::~ConcreteBuilder(){

}
void ConcreteBuilder::buildPartA(){
m_prod->setA("A Style "); //不同的建造者,可以實現(xiàn)不同產(chǎn)品的建造
}
void ConcreteBuilder::buildPartB(){
m_prod->setB("B Style ");
}
void ConcreteBuilder::buildPartC(){
m_prod->setC("C style ");
}

include "Director.h"

Director::Director(){
}
Director::~Director(){
}
Product* Director::constuct(){
m_pbuilder->buildPartA();
m_pbuilder->buildPartB();
m_pbuilder->buildPartC();

return m_pbuilder->getResult();

}
void Director::setBuilder(Builder* buider){
m_pbuilder = buider;
}

include <iostream>

include "ConcreteBuilder.h"

include "Director.h"

include "Builder.h"

include "Product.h"

using namespace std;

int main(int argc, char *argv[])
{
ConcreteBuilder * builder = new ConcreteBuilder();
Director director;
director.setBuilder(builder);
Product * pd = director.constuct();
pd->show();

delete builder;
delete pd;
return 0;

}

######4.5模式分析
抽象建造者類中定義了產(chǎn)品的創(chuàng)建方法和返回方法;

建造者模式的結(jié)構(gòu)中還引入了一個指揮者類Director,該類的作用主要有兩個:一方面它隔離了客戶與生產(chǎn)過程;另一方面它負責(zé)控制產(chǎn)品的生成過程。指揮者針對抽象建造者編程,客戶端只需要知道具體建造者的類型,即可通過指揮者類調(diào)用建造者的相關(guān)方法,返回一個完整的產(chǎn)品對象

在客戶端代碼中,無須關(guān)心產(chǎn)品對象的具體組裝過程,只需確定具體建造者的類型即可,建造者模式將復(fù)雜對象的構(gòu)建與對象的表現(xiàn)分離開來,這樣使得同樣的構(gòu)建過程可以創(chuàng)建出不同的表現(xiàn)。
######4.6優(yōu)點
- 在建造者模式中, 客戶端不必知道產(chǎn)品內(nèi)部組成的細節(jié),將產(chǎn)品本身與產(chǎn)品的創(chuàng)建過程解耦,使得相同的創(chuàng)建過程可以創(chuàng)建不同的產(chǎn)品對象。
- 每一個具體建造者都相對獨立,而與其他的具體建造者無關(guān),因此可以很方便地替換具體建造者或增加新的具體建造者, 用戶使用不同的具體建造者即可得到不同的產(chǎn)品對象 。
- 可以更加精細地控制產(chǎn)品的創(chuàng)建過程 。將復(fù)雜產(chǎn)品的創(chuàng)建步驟分解在不同的方法中,使得創(chuàng)建過程更加清晰,也更方便使用程序來控制創(chuàng)建過程。
- 增加新的具體建造者無須修改原有類庫的代碼,指揮者類針對抽象建造者類編程,系統(tǒng)擴展方便,符合“開閉原則”。

######4.7缺點
- 建造者模式所創(chuàng)建的產(chǎn)品一般具有較多的共同點,其組成部分相似,如果產(chǎn)品之間的差異性很大,則不適合使用建造者模式,因此其使用范圍受到一定的限制。
- 如果產(chǎn)品的內(nèi)部變化復(fù)雜,可能會導(dǎo)致需要定義很多具體建造者類來實現(xiàn)這種變化,導(dǎo)致系統(tǒng)變得很龐大。

######4.8適用環(huán)境

在以下情況下可以使用建造者模式:

- 需要生成的產(chǎn)品對象有復(fù)雜的內(nèi)部結(jié)構(gòu),這些產(chǎn)品對象通常包含多個成員屬性。
- 需要生成的產(chǎn)品對象的屬性相互依賴,需要指定其生成順序。
- 對象的創(chuàng)建過程獨立于創(chuàng)建該對象的類。在建造者模式中引入了指揮者類,將創(chuàng)建過程封裝在指揮者類中,而不在建造者類中。
- 隔離復(fù)雜對象的創(chuàng)建和使用,并使得相同的創(chuàng)建過程可以創(chuàng)建不同的產(chǎn)品。

######4.9模式應(yīng)用

在很多游戲軟件中,地圖包括天空、地面、背景等組成部分,人物角色包括人體、服裝、裝備等組成部分,可以使用建造者模式對其進行設(shè)計,通過不同的具體建造者創(chuàng)建不同類型的地圖或人物。

#######4.10模式擴展
建造者模式的簡化:
省略抽象建造者角色:如果系統(tǒng)中只需要一個具體建造者的話,可以省略掉抽象建造者。
省略指揮者角色:在具體建造者只有一個的情況下,如果抽象建造者角色已經(jīng)被省略掉,那么還可以省略指揮者角色,讓
Builder角色扮演指揮者與建造者雙重角色。

建造者模式與抽象工廠模式的比較:

與抽象工廠模式相比, 建造者模式返回一個組裝好的完整產(chǎn)品 ,而 抽象工廠模式返回一系列相關(guān)的產(chǎn)品,這些產(chǎn)品位于不同的產(chǎn)品等級結(jié)構(gòu),構(gòu)成了一個產(chǎn)品族。
在抽象工廠模式中,客戶端實例化工廠類,然后調(diào)用工廠方法獲取所需產(chǎn)品對象,而在建造者模式中,客戶端可以不直接調(diào)用建造者的相關(guān)方法,而是通過指揮者類來指導(dǎo)如何生成對象,包括對象的組裝過程和建造步驟,它側(cè)重于一步步構(gòu)造一個復(fù)雜對象,返回一個完整的對象。
如果將抽象工廠模式看成 汽車配件生產(chǎn)工廠 ,生產(chǎn)一個產(chǎn)品族的產(chǎn)品,那么建造者模式就是一個 汽車組裝工廠 ,通過對部件的組裝可以返回一輛完整的汽車。

######4.11總結(jié)
- 建造者模式將一個復(fù)雜對象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。建造者模式是一步一步創(chuàng)建一個復(fù)雜的對象,它允許用戶只通過指定復(fù)雜對象的類型和內(nèi)容就可以構(gòu)建它們,用戶不需要知道內(nèi)部的具體構(gòu)建細節(jié)。建造者模式屬于對象創(chuàng)建型模式。
- 建造者模式包含如下四個角色:抽象建造者為創(chuàng)建一個產(chǎn)品對象的各個部件指定抽象接口;具體建造者實現(xiàn)了抽象建造者接口,實現(xiàn)各個部件的構(gòu)造和裝配方法,定義并明確它所創(chuàng)建的復(fù)雜對象,也可以提供一個方法返回創(chuàng)建好的復(fù)雜產(chǎn)品對象;產(chǎn)品角色是被構(gòu)建的復(fù)雜對象,包含多個組成部件;指揮者負責(zé)安排復(fù)雜對象的建造次序,指揮者與抽象建造者之間存在關(guān)聯(lián)關(guān)系,可以在其construct()建造方法中調(diào)用建造者對象的部件構(gòu)造與裝配方法,完成復(fù)雜對象的建造
- 在建造者模式的結(jié)構(gòu)中引入了一個指揮者類,該類的作用主要有兩個:一方面它隔離了客戶與生產(chǎn)過程;另一方面它負責(zé)控制產(chǎn)品的生成過程。指揮者針對抽象建造者編程,客戶端只需要知道具體建造者的類型,即可通過指揮者類調(diào)用建造者的相關(guān)方法,返回一個完整的產(chǎn)品對象。
- 建造者模式的主要優(yōu)點在于客戶端不必知道產(chǎn)品內(nèi)部組成的細節(jié),將產(chǎn)品本身與產(chǎn)品的創(chuàng)建過程解耦,使得相同的創(chuàng)建過程可以創(chuàng)建不同的產(chǎn)品對象,每一個具體建造者都相對獨立,而與其他的具體建造者無關(guān),因此可以很方便地替換具體建造者或增加新的具體建造者,符合“開閉原則”,還可以更加精細地控制產(chǎn)品的創(chuàng)建過程;其主要缺點在于由于建造者模式所創(chuàng)建的產(chǎn)品一般具有較多的共同點,其組成部分相似,因此其使用范圍受到一定的限制,如果產(chǎn)品的內(nèi)部變化復(fù)雜,可能會導(dǎo)致需要定義很多具體建造者類來實現(xiàn)這種變化,導(dǎo)致系統(tǒng)變得很龐大。
- 建造者模式適用情況包括:需要生成的產(chǎn)品對象有復(fù)雜的內(nèi)部結(jié)構(gòu),這些產(chǎn)品對象通常包含多個成員屬性;需要生成的產(chǎn)品對象的屬性相互依賴,需要指定其生成順序;對象的創(chuàng)建過程獨立于創(chuàng)建該對象的類;隔離復(fù)雜對象的創(chuàng)建和使用,并使得相同的創(chuàng)建過程可以創(chuàng)建不同類型的產(chǎn)品。

##單例模式

######5.1模式動機
- 對于系統(tǒng)中的某些類來說,只有一個實例很重要,例如,一個系統(tǒng)中可以存在多個打印任務(wù),但是只能有一個正在工作的任務(wù);一個系統(tǒng)只能有一個窗口管理器或文件系統(tǒng);一個系統(tǒng)只能有一個計時工具或ID(序號)生成器。
- 如何保證一個類只有一個實例并且這個實例易于被訪問呢?定義一個全局變量可以確保對象隨時都可以被訪問,但不能防止我們實例化多個對象。
一個更好的解決辦法是讓類自身負責(zé)保存它的唯一實例。這個類可以保證沒有其他實例被創(chuàng)建,并且它可以提供一個訪問該實例的方法。這就是單例模式的模式動機。

######5.2.模式定義
- 單例模式(Singleton Pattern):單例模式確保某一個類只有一個實例,而且自行實例化并向整個系統(tǒng)提供這個實例,這個類稱為單例類,它提供全局訪問的方法。
- 單例模式的要點有三個:一是某個類只能有一個實例;二是它必須自行創(chuàng)建這個實例;三是它必須自行向整個系統(tǒng)提供這個實例。單例模式是一種對象創(chuàng)建型模式。單例模式又名單件模式或單態(tài)模式。
######5.3模式結(jié)構(gòu)

- singleton:單例

![Singleton.jpg](http://upload-images.jianshu.io/upload_images/4979809-1ccbf7a29a945a16.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

######5.3代碼

include "Singleton.h"

include <iostream>

using namespace std;
Singleton * Singleton::instance = NULL;
Singleton::Singleton(){
}

Singleton::~Singleton(){
delete instance;
}
Singleton* Singleton::getInstance(){
if (instance == NULL)
{
instance = new Singleton();
}

return  instance;

}
void Singleton::singletonOperation(){
cout << "singletonOperation" << endl;
}

int main(int argc, char *argv[])
{
Singleton * sg = Singleton::getInstance();
sg->singletonOperation();
return 0;
}

######5.6模式分析
單例模式的目的是保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。單例模式包含的角色只有一個,就是單例類——Singleton。單例類擁有一個私有構(gòu)造函數(shù),確保用戶無法通過new關(guān)鍵字直接實例化它。除此之外,該模式中包含一個靜態(tài)私有成員變量與靜態(tài)公有的工廠方法,該工廠方法負責(zé)檢驗實例的存在性并實例化自己,然后存儲在靜態(tài)成員變量中,以確保只有一個實例被創(chuàng)建。

在單例模式的實現(xiàn)過程中,需要注意如下三點:

- 單例類的構(gòu)造函數(shù)為私有;
- 提供一個自身的靜態(tài)私有成員變量;
- 提供一個公有的靜態(tài)工廠方法

######5.7實例

在操作系統(tǒng)中,打印池(Print Spooler)是一個用于管理打印任務(wù)的應(yīng)用程序,通過打印池用戶可以刪除、中止或者改變打印任務(wù)的優(yōu)先級,在一個系統(tǒng)中只允許運行一個打印池對象,如果重復(fù)創(chuàng)建打印池則拋出異?!,F(xiàn)使用單例模式來模擬實現(xiàn)打印池的設(shè)計。

######5.8. 優(yōu)點
- 提供了對唯一實例的受控訪問。因為單例類封裝了它的唯一實例,所以它可以嚴格控制客戶怎樣以及何時訪問它,并為設(shè)計及開發(fā)團隊提供了共享的概念。
- 由于在系統(tǒng)內(nèi)存中只存在一個對象,因此可以節(jié)約系統(tǒng)資源,對于一些需要頻繁創(chuàng)建和銷毀的對象,單例模式無疑可以提高系統(tǒng)的性能。
- 允許可變數(shù)目的實例。我們可以基于單例模式進行擴展,使用與單例控制相似的方法來獲得指定個數(shù)的對象實例。

#####5.9. 缺點
- 由于單例模式中沒有抽象層,因此單例類的擴展有很大的困難。
- 單例類的職責(zé)過重,在一定程度上違背了“單一職責(zé)原則”。因為單例類既充當(dāng)了工廠角色,提供了工廠方法,同時又充當(dāng)了產(chǎn)品角色,包含一些業(yè)務(wù)方法,將產(chǎn)品的創(chuàng)建和產(chǎn)品的本身的功能融合到一起。
- 濫用單例將帶來一些負面問題,如為了節(jié)省資源將數(shù)據(jù)庫連接池對象設(shè)計為單例類,可能會導(dǎo)致共享連接池對象的程序過多而出現(xiàn)連接池溢出;現(xiàn)在很多面向?qū)ο笳Z言(如Java、C#)的運行環(huán)境都提供了自動垃圾回收的技術(shù),因此,如果實例化的對象長時間不被利用,系統(tǒng)會認為它是垃圾,會自動銷毀并回收資源,下次利用時又將重新實例化,這將導(dǎo)致對象狀態(tài)的丟失。

######5.10. 適用環(huán)境
在以下情況下可以使用單例模式:
系統(tǒng)只需要一個實例對象,如系統(tǒng)要求提供一個唯一的序列號生成器,或者需要考慮資源消耗太大而只允許創(chuàng)建一個對象。
客戶調(diào)用類的單個實例只允許使用一個公共訪問點,除了該公共訪問點,不能通過其他途徑訪問該實例。
在一個系統(tǒng)中要求一個類只有一個實例時才應(yīng)當(dāng)使用單例模式。反過來,如果一個類可以有幾個實例共存,就需要對單例模式進行改進,使之成為多例模式

######5.11. 模式應(yīng)用
一個具有自動編號主鍵的表可以有多個用戶同時使用,但數(shù)據(jù)庫中只能有一個地方分配下一個主鍵編號,否則會出現(xiàn)主鍵重復(fù),因此該主鍵編號生成器必須具備唯一性,可以通過單例模式來實現(xiàn)。



######5.13. 總結(jié)
- 單例模式確保某一個類只有一個實例,而且自行實例化并向整個系統(tǒng)提供這個實例,這個類稱為單例類,它提供全局訪問的方法。單例模式的要點有三個:一是某個類只能有一個實例;二是它必須自行創(chuàng)建這個實例;三是它必須自行向整個系統(tǒng)提供這個實例。單例模式是一種對象創(chuàng)建型模式。
- 單例模式只包含一個單例角色:在單例類的內(nèi)部實現(xiàn)只生成一個實例,同時它提供一個靜態(tài)的工廠方法,讓客戶可以使用它的唯一實例;為了防止在外部對其實例化,將其構(gòu)造函數(shù)設(shè)計為私有。
- 單例模式的目的是保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。單例類擁有一個私有構(gòu)造函數(shù),確保用戶無法通過new關(guān)鍵字直接實例化它。除此之外,該模式中包含一個靜態(tài)私有成員變量與靜態(tài)公有的工廠方法。該工廠方法負責(zé)檢驗實例的存在性并實例化自己,然后存儲在靜態(tài)成員變量中,以確保只有一個實例被創(chuàng)建。
- 單例模式的主要優(yōu)點在于提供了對唯一實例的受控訪問并可以節(jié)約系統(tǒng)資源;其主要缺點在于因為缺少抽象層而難以擴展,且單例類職責(zé)過重。
- 單例模式適用情況包括:系統(tǒng)只需要一個實例對象;客戶調(diào)用類的單個實例只允許使用一個公共訪問點。






最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容