本文主要論述瞭如下幾方面:程序員
1.總論編程
2.簡單工廠模式設計模式
3.工廠方法模式ide
4.抽象工廠模式函數
在工廠設計模式中,客戶端能夠請求一個對象,而無需知道這個對象來自哪裏;也就是說,使用哪一個類來生成這個對象。工廠背後的思想是簡化對象的建立。與客戶端本身基於類實例化直接建立對象相比,基於一箇中心化函數來實現,更易於追蹤建立了哪些對象。經過將建立對象的代碼和使用對象的代碼解耦,工廠可以下降應用維護的複雜度。
工廠一般有兩種形式:一種是工廠方法( Factory Method),它是一個方法,對不一樣的輸入參數返回不一樣的對象;第二種是抽象工廠,它是一組用於建立一系列相關事物對象的工廠方法。
工廠模式分類:spa
這三種模式從上到下逐步抽象,而且更具通常性。
三者區別:
工廠方法模式:簡單工廠模式可視爲工廠方法的一種特例。一個抽象產品類,能夠派生出多個具體產品類。 一個抽象工廠類,能夠派生出多個具體工廠類。 每一個具體工廠類只能建立一個具體產品類的實例。
抽象工廠模式:多個抽象產品類,每一個抽象產品類能夠派生出多個具體產品類。 一個抽象工廠類,能夠派生出多個具體工廠類。 每一個具體工廠類能夠建立多個具體產品類的實例。
總結:
工廠方法模式只有一個抽象產品類,而抽象工廠模式有多個。
工廠方法模式的具體工廠類只能建立一個具體產品類的實例,而抽象工廠模式能夠建立多個。設計
創建一個一個工廠來製造新的對象。它存在的目的很簡單:定義一個用於建立對象的接口。 3d
按照面向過程的習慣,可能直接在客戶端中根據條件來建立不一樣的具體產品實例;對於簡單工廠模式而言,是把這部分邏輯抽象出來,放在一個工廠類中,由工廠類負責產生具體的對象,也就是將生產者和消費者分離了。code
簡單工廠模式,經過專門定義一個類來負責建立具體類型的實例,要建立的實例通常繼承自同一個類;對象
結構通常以下所示:
如上所示,工廠模式中的角色通常包括:
工廠角色:即上圖中的OperationFactory,它能夠被客戶端調用,其內部負責建立具體的對象;
class OperationFactory: # 定義一個工廠,根據用戶輸入來生產實例對象 operator = {} operator["+"] = OperationAdd() operator["-"] = OperationSub() operator["*"] = OperationMul() operator["/"] = OperationDiv() def createOperation(self, ch): if ch in self.operator: op = self.operator[ch] else: op = OperationUndef() return op
抽象產品類:即上圖中的抽象類Operation,它描述了全部實例公共的接口;
class Operation: # 基類,全部操做類都今後類繼承 def GetResult(self): pass
具體產品類:即上圖中的OperationAdd等,實現抽象產品的接口,是工廠角色中要建立的具體實例
class OperationAdd(Operation): # 加法類 def GetResult(self): return self.op1 + self.op2 class OperationSub(Operation): # 減法類 def GetResult(self): return self.op1 - self.op2 class OperationMul(Operation): # 乘法類 def GetResult(self): return self.op1 * self.op2 class OperationDiv(Operation): # 除法類 def GetResult(self): try: result = self.op1 / self.op2 return result except ZeroDivisionError as e: print("error:divided by zero.",e) return 0
主函數實現:
if __name__ == "__main__": op = input("operator: ") opa = int(input("a: ")) opb = int(input("b: ")) factory = OperationFactory() cal = factory.createOperation(op) cal.op1 = opa cal.op2 = opb print(cal.GetResult())
簡單工廠優缺點總結:
優勢:從上面的描述能夠看出,工廠角色負責產生具體的實例對象,因此在工廠類中須要有必要的邏輯,經過客戶的輸入可以獲得具體建立的實例;因此客戶端就不須要感知具體對象是怎麼產生的,只須要將必要的信息提供給工廠便可;
缺點:簡單工廠模式是違反「開閉原則」,即對擴展開放,對修改關閉;由於若是要新增具體產品,就須要修改工廠類的代碼;
下面咱們從開閉原則上來分析下簡單工廠模式。當客戶再也不知足現有功能的時候,想要一個開方操做,只要這種操做符合抽象產品制定的合同,那麼只要通知工廠類知道就能夠被客戶使用了。因此對產品部分來講,它是符合開閉原則的;可是工廠部分好像不太理想,由於每增長一種操做,都要在工廠類(OperationFactory)中增長相應的建立業務邏輯(方法須要新增case來判斷建立什麼樣的操做),這顯然是違背開閉原則的。可想而知對於新產品的加入,工廠類是很被動的。對於這樣的工廠類,咱們稱它爲全能類 或者上帝類。
咱們舉的例子是最簡單的狀況,而在實際應用中,極可能產品是一個多層次的樹狀結構。因爲簡單工廠模式中只有一個工廠類來對應這些產品,因此這可能會把咱們的上帝累壞了,也累壞了咱們這些程序員。因而工廠方法模式做爲救世主出現了。 工廠類定義成了接口,而每新增的操做,就增長該種類型對應工廠類的實現,這樣工廠的設計就能夠擴展了,而沒必要去修改原來的代碼。
工廠方法模式:定義一個用於建立對象的接口,讓子類決定實例化哪個類。工廠方法讓類把實例化推遲到了子類。
對於簡單工廠而言,建立對象的邏輯判斷放在了工廠類中,客戶不感知具體的類,可是工廠類違反了開閉原則,若是要新增新的具體類,就必須修改工廠類;
對於工廠模式而言,是經過擴展來新增具體類的,可是在客戶端就必須感知到具體的類了,要經過具體類的建立工廠來建立具體的實例,也就是判斷邏輯由簡單工廠的工廠類挪到了客戶端中;
工廠模式橫向擴展很方便;
結構通常以下所示:
工廠方法模式組成:
1)抽象工廠角色: 這是工廠方法模式的核心,它與應用程序無關。是具體工廠角色必須實現的接口或者必須繼承的父類。
import abc class Creator(metaclass=abc.ABCMeta): """ Declare the factory method, which returns an object of type Product. Creator may also define a default implementation of the factory method that returns a default ConcreteProduct object. Call the factory method to create a Product object. """ def __init__(self): self.product = self._factory_method() @abc.abstractmethod def _factory_method(self): pass def some_operation(self): self.product.interface()
2)具體工廠角色:它含有和具體業務邏輯有關的代碼。由應用程序調用以建立對應的具體產品的對象。
class ConcreteCreator1(Creator): """ Override the factory method to return an instance of a ConcreteProduct1. """ def _factory_method(self): return ConcreteProduct1() class ConcreteCreator2(Creator): """ Override the factory method to return an instance of a ConcreteProduct2. """ def _factory_method(self): return ConcreteProduct2()
3)抽象產品角色:它是具體產品繼承的父類或者是實現的接口。
import abc class Product(metaclass=abc.ABCMeta): """ Define the interface of objects the factory method creates. """ @abc.abstractmethod def interface(self): pass
4)具體產品角色:具體工廠角色所建立的對象就是此角色的實例。
class ConcreteProduct1(Product): """ Implement the Product interface. """ def interface(self): pass class ConcreteProduct2(Product): """ Implement the Product interface. """ def interface(self): pass
主函數實現:
def main(): concrete_creator = ConcreteCreator1() concrete_creator.product.interface() concrete_creator.some_operation() if __name__ == "__main__": main()
這個和簡單工廠有區別,簡單工廠模式只有一個工廠,工廠方法模式對每個產品都有相應的工廠。
工廠方法模式使用繼承自抽象工廠角色的多個子類來代替簡單工廠模式中的「上帝類」。正如上面所說,這樣便分擔了對象承受的壓力;並且這樣使得結構變得靈活起來——當有新的產品產生時,只要按照抽象產品角色、抽象工廠角色提供的合同來生成,那麼就能夠被客戶使用,而沒必要去修改任何已有 的代碼。能夠看出工廠角色的結構也是符合開閉原則的!
工廠方法模式優缺點總結:
優勢:1.增長一個產品,只須要增長產品類和對應的工廠類,而沒必要修改總的工廠類。可使代碼結構清晰,有效地封裝變化。
2.對調用者屏蔽具體的產品類。若是使用工廠模式,調用者只關心產品的接口就能夠了,至於具體的實現,調用者根本無需關心。即便變動了具體的實現,對調用者來講沒有任何影響。
3.下降耦合度。產品類的實例化一般來講是很複雜的,它須要依賴不少的類,而這些類對於調用者來講根本無需知道,若是使用了工廠方法,咱們須要作的僅僅是實例化好產品類,而後交給調用者使用。對調用者來講,產品所依賴的類都是透明的。
缺點:增長新的產品類,會修改客戶端代碼,工廠方法只是把簡單工廠的內部邏輯判斷移到了客戶端進行。簡單對象,特別是只須要經過new就能夠完成建立的對象,無需使用工廠模式。若是使用工廠模式,就須要引入一個工廠類,會增長系統的複雜度。
能夠看出工廠方法的加入,使得對象的數量成倍增加。當產品種類很是多時,會出現大量的與之對應的工廠對象,這不是咱們所但願的。由於若是不能避免這種情 況,能夠考慮使用簡單工廠模式與工廠方法模式相結合的方式來減小工廠類:即對於產品樹上相似的種類(通常是樹的葉子中互爲兄弟的)使用簡單工廠模式來實 現。
工廠方法模式應用場景:
抽象工廠設計模式是抽象方法的一種泛化。歸納來講,一個抽象工廠是(邏輯上的)一組工廠方法,其中的每一個工廠方法負責產生不一樣種類的對象。
能夠說,抽象工廠模式和工廠方法模式的區別就在於須要建立對象的複雜程度上。並且抽象工廠模式是三個裏面最爲抽象、最具通常性的。
抽象工廠模式的用意爲:給客戶端提供一個接口,能夠建立多個產品族中的產品對象 ,並且使用抽象工廠模式還要知足一下條件:
抽象工廠模式與工廠方法模式的區別:
抽象工廠模式是工廠方法模式的升級版本,他用來建立一組相關或者相互依賴的對象。他與工廠方法模式的區別就在於,工廠方法模式針對的是一個產品等級結構;而抽象工廠模式則是針對的多個產品等級結構。在編程中,一般一個產品結構,表現爲一個接口或者抽象類,也就是說,工廠方法模式提供的全部產品都是衍生自同一個接口或抽象類,而抽象工廠模式所提供的產品則是衍生自不一樣的接口或抽象類。
在抽象工廠模式中,有一個產品族的概念:所謂的產品族,是指位於不一樣產品等級結構中功能相關聯的產品組成的家族。抽象工廠模式所提供的一系列產品就組成一個產品族;而工廠方法提供的一系列產品稱爲一個等級結構。咱們拿生產汽車的例子來講明他們之間的區別。
在上面的類圖中,兩廂車和三廂車稱爲兩個不一樣的等級結構;而2.0排量車和2.4排量車則稱爲兩個不一樣的產品族。再具體一點,2.0排量兩廂車和2.4排量兩廂車屬於同一個等級結構,2.0排量三廂車和2.4排量三廂車屬於另外一個等級結構;而2.0排量兩廂車和2.0排量三廂車屬於同一個產品族,2.4排量兩廂車和2.4排量三廂車屬於另外一個產品族。
明白了等級結構和產品族的概念,就理解工廠方法模式和抽象工廠模式的區別了,若是工廠的產品所有屬於同一個等級結構,則屬於工廠方法模式;若是工廠的產品來自多個等級結構,則屬於抽象工廠模式。在本例中,若是一個工廠模式提供2.0排量兩廂車和2.4排量兩廂車,那麼他屬於工廠方法模式;若是一個工廠模式是提供2.4排量兩廂車和2.4排量三廂車兩個產品,那麼這個工廠模式就是抽象工廠模式,由於他提供的產品是分屬兩個不一樣的等級結構。固然,若是一個工廠提供所有四種車型的產品,由於產品分屬兩個等級結構,他固然也屬於抽象工廠模式了。
結構通常以下所示:
抽象工廠模式的各個角色(和工廠方法同樣):
import abc class AbstractFactory(metaclass=abc.ABCMeta): """ Declare an interface for operations that create abstract product objects. """ @abc.abstractmethod def create_product_a(self): pass @abc.abstractmethod def create_product_b(self): pass
class ConcreteFactory1(AbstractFactory): """ Implement the operations to create concrete product objects. """ def create_product_a(self): return ConcreteProductA1() def create_product_b(self): return ConcreteProductB1() class ConcreteFactory2(AbstractFactory): """ Implement the operations to create concrete product objects. """ def create_product_a(self): return ConcreteProductA2() def create_product_b(self): return ConcreteProductB2()
class AbstractProductA(metaclass=abc.ABCMeta): """ Declare an interface for a type of product object. """ @abc.abstractmethod def interface_a(self): pass
class ConcreteProductA1(AbstractProductA): """ Define a product object to be created by the corresponding concrete factory. Implement the AbstractProduct interface. """ def interface_a(self): pass class ConcreteProductA2(AbstractProductA): """ Define a product object to be created by the corresponding concrete factory. Implement the AbstractProduct interface. """ def interface_a(self): pass
class ConcreteProductB1(AbstractProductB): """ Define a product object to be created by the corresponding concrete factory. Implement the AbstractProduct interface. """ def interface_b(self): pass class ConcreteProductB2(AbstractProductB): """ Define a product object to be created by the corresponding concrete factory. Implement the AbstractProduct interface. """ def interface_b(self): pass
主函數實現:
def main(): for factory in (ConcreteFactory1(), ConcreteFactory2()): product_a = factory.create_product_a() product_b = factory.create_product_b() product_a.interface_a() product_b.interface_b() if __name__ == "__main__": main()
抽象工廠模式的優缺點:
優勢: 抽象工廠模式除了具備工廠方法模式的優勢外,最主要的優勢就是能夠在類的內部對產品族進行約束。所謂的產品族,通常或多或少的都存在必定的關聯,抽象工廠模式就能夠在類內部對產品族的關聯關係進行定義和描述,而沒必要專門引入一個新的類來進行管理。
缺點:產品族的擴展將是一件十分費力的事情,假如產品族中須要增長一個新的產品,則幾乎全部的工廠類都須要進行修改。因此使用抽象工廠模式時,對產品等級結構的劃分是很是重要的。
適用場景:
當須要建立的對象是一系列相互關聯或相互依賴的產品族時,即可以使用抽象工廠模式。說的更明白一點,就是一個繼承體系中,若是存在着多個等級結構(即存在着多個抽象類),而且分屬各個等級結構中的實現類之間存在着必定的關聯或者約束,就可使用抽象工廠模式。假如各個等級結構中的實現類之間不存在關聯或約束,則使用多個獨立的工廠來對產品進行建立,則更合適一點。
總結,不管是簡單工廠模式,工廠方法模式,仍是抽象工廠模式,他們都屬於工廠模式,在形式和特色上也是極爲類似的,他們的最終目的都是爲了解耦。在使用時,咱們沒必要去在乎這個模式到底工廠方法模式仍是抽象工廠模式,由於他們之間的演變經常是使人琢磨不透的。常常你會發現,明明使用的工廠方法模式,當新需求來臨,稍加修改,加入了一個新方法後,因爲類中的產品構成了不一樣等級結構中的產品族,它就變成抽象工廠模式了;而對於抽象工廠模式,當減小一個方法使的提供的產品再也不構成產品族以後,它就演變成了工廠方法模式。
因此,在使用工廠模式時,只須要關心下降耦合度的目的是否達到了。