設計模式解析

工廠模式

工廠模式在“創造模式”中與其它模式相比,有其難點,困難之處並不是工廠模式的定義本身,令人困惑的地方在於爲什麼要使用工廠模式,或者說是必須使用工廠的理由。


工廠模式的定義

爲創建某個目標類實例定義一個接口,由此接口的類實現對目標類的實例化。(此接口即工廠接口,IFactory)

(Define an interface for creating an object, but let the classes that implement the interface decide which class to instantiate. )

工廠(方法)模式派生目標類的實例化在其工廠接口子類中
(The Factory method lets a class defer instantiation to subclasses.)


wKioL1R6wLjBoOjzAADfROTPUUw444.jpg


對於使用工廠模式的疑問在於,產品類所定義產品實體是在客戶邏輯中真正使用的目標,如果產品類已經抽象,使用者只需要將產品的子類實例化後使用產品的接口或父類,爲什麼一定要使用工廠類,多此一舉

即使使用工廠類,實際上是工廠的子類去實例化具體的產品,對於使用者來說,去判斷使用哪一個工廠和去判斷使用哪一個產品沒有本質的區別,爲什麼在設計的時候還需要加入工廠的接口,和工廠的繼承類,增加複雜度呢。


關鍵的問題在於工廠模式定義中的最後一句,工廠的子類決定如何實現子產品,實現局域化和特性化的產品。


產品的實例化,指的是子產品的實例化,子產品在實現的時候,是不是需要有特性化和局域化的需求,成爲是否使用工廠模式的判斷標準


更簡單的說,如果所有的產品在的實例化只是一個簡單的new,可以解決,那使用工廠就完全是多此一舉。而各種產品,雖然可以維持統一接口, 但在實例化時是需要不同的,甚至複雜的處理,或者更復雜的邏輯處理,那麼,工廠的目的就是,將複雜的不同的實例化邏輯統一成統一的接口,來屏蔽使用者對於實例化產品是對其複雜邏輯的理解與實現,而統一使用簡單的工廠接口。


就以圖中類爲例

class Light{
public:

Light(){}

virtual void TurnOn() = 0;
}

class BulbLight : public {
public:

BulbLight()

void TurnOn() {


// power 5v

}
}
class TubeLight : public {
public:

TubeLight(){}

void TurnOn(){


// power 220v

}
}


如果做兩個工廠類BulbFactory和TubeFactory對BulbLight和TubeLight進行實例化,使用者仍然需要決定並實現Factory的實例,這同實現具體的Light類沒有區別,也沒有益處,反而增加工作量和複雜度。

然而,Light子類的構造變得複雜時,情況變不一樣了

class BulbLight : public {

Power power;
public:

BulbLight(Power bettery) : power(bettery) {}

void Fill(Gas current_gas);

void TurnOn() {


// power 5v

}
}
class TubeLight : public {

Cable wire;
public:

TubeLight(Cable power) : wire(power) {}

void TurnOn(){


// power 220v

}
}

對於使用者來說,不去向BulbLight和TubeLight的設計者(文檔)瞭解實例化的細節,將很難使用兩個子類

這將是Factory的優勢所在,Light子類的設計者,同時提供Factory接口的產品實例化方法,屏蔽了產品本身實例化的複雜邏輯

如果實例化之後還有其他本地化的邏輯,如Fill之類,工廠模式的特性會更具體的體現出來。



對抽象工廠模式的理解,主要問題在與工廠模式的區別

僅就定義圖和繼承關係來看,二者基本上沒有區別

但兩個模式的定義給出了非常清晰的解釋,簡單的說,他們所關注的問題層次完全不同


抽象工廠的定義

爲創建一組相關性目標實例提供接口而無須指定具體目標類

(Provide an interface for creating families of related or dependent objects without specifying their concrete classes.)


結構示例圖


Abstract factory UML.svg


工廠模式,關注的是特定產品實例化的簡化接口,抽象工廠關注的是產品集合的接口化和工廠本身的統一管理

最簡單的實例可以考慮爲,將一個系統或程序移植到另一個環境或操作系統時所遇到的問題。


可以想象,在不使用抽象工廠的場景中,所有目標實體的實例化都使用new去具體實現

那麼,遇到系統移植的需要時,有兩種方案可供選擇

一是修改所有實體類的代碼,使其適應新系統,新環境,這樣可以保證使用者(實例化的地方)使用邏輯不變

第二種方法是設計一套新的實體類,使用不同的命名,替代原來使用邏輯中的實例化代碼,全部使用新的類名

這兩種方法無論哪種,其修改工作量都不容小視,代碼的安全(運行)性也受到威脅


抽象工廠模式意圖解決這類問題中實體類集體替換的問題

對於上面兩種方法的修改是,使用抽象工廠的統一接口創建目標對象,實例的使用者實例化時只使用抽象工廠接口

這種方法在第一次系統移植時工作量會有所增加(與以上兩種方法相比),而在第三次或之後的移植中會體現出優勢

而如果,在系統原始設計時即使用抽象工廠模式,則對新系統適應性的修改只體現在新建一批目標類上,從而受益良多


抽象工廠與工廠模式並不重疊,也不矛盾,他們試圖解決不同的問題,不同層次的問題

工廠本身專注於如何簡化可替代產品的實例化過程,抽象工廠希望通過對工廠的接口化管理,簡化產品集羣的管理

抽象工廠的名稱容易使概念混亂,其意義更像實際生活中的企業集團

集團可以兼併製造類似產品的多個工廠,工廠生產的規格和標準在集團內統一,即抽象工廠的接口(IAbstractFactory)

從這個意義上講,命名這個模式爲集團模式可能更加容易理解一些


建造者模式中的兩個概念,指揮者和建造者定義比較清晰並不難理解。

模式定義


將創建複雜目標實體的工作分離,保持相同製造流程的情況下,創建不同的目標實例

Separate the construction of a complex object from its representation. By doing so the same construction process can create different representations.


施工模式中的一個關鍵概念是目標實體的複雜性,模式的目的就是將複雜實體的構建過程抽象和統一起來,可以由一個預先定義好的流水線管理


Builder Structure

如示例圖中所描述,複雜實體作爲最後產出物,從創建者的getResult獲取

很有趣的是,建造者的接口中並不定義獲取產品getResult的接口,原因是施工模式關注的只是對製作過程的管理,而不是對產品本身繼承性的管理(產品的管理,由兩個工廠類考慮)


指揮者對構造過程(流水線)的管理在construct中實現,建造者的實體類負責具體實體的創建

使用者選擇具體需要的建造者,同時使用預先定義好的指揮者(構造流水construct實際上可以是靜態的)

最終的產品實例是從實際創建類中直接獲取,因爲與建造過程無關


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