【Python設計模式】03 工廠模式:建立建立物件的工廠
三、工廠模式:建立建立物件的工廠
工廠模式可以說是最常用的設計模式
本章主要介紹建立型設計模式:工廠模式
本章主題
- 瞭解簡單工廠設計模式
- 討論工廠方法和抽象工廠方法及其差異
- 利用Python 程式碼實現真實場景
- 討論模式的優缺點並進行相應的比較
1. 瞭解工廠模式
面向物件程式設計中,‘工廠’ 表示一個負責建立其他型別物件的類
工廠與客戶端的關係:
- 工廠的類建立一個物件以及與這個物件關聯的多個方法
- 客戶端使用某些引數呼叫此方法
- 工廠會據此建立所需型別的物件,然後將它們返回給客戶端
那麼問題是為什麼不能是客戶端直接建立物件呢?工廠的優點在於:
- 鬆耦合,即物件的建立可以獨立於類的實現
- 客戶端無需瞭解建立物件的類,只需要知道需要傳遞的介面、方法和引數,簡化了客戶端的實現
- 輕鬆地在工廠中新增其他類來建立其他型別的物件,而這無需更改客戶端程式碼
- 工廠可以重用現有物件。但是客戶端建立物件總是建立一個新的物件
Factory 設計模式有三種變體:
- 簡單工廠模式:允許介面建立物件,但不會暴露物件的建立邏輯
- 工廠方法模式:允許介面建立物件,但使用哪個類來建立物件,則交由子類決定
- 抽象工廠模式:抽象工廠是一個能夠建立一系列相關物件而無需指定/公開其具體類的介面。該模式能夠提供其他工廠的物件,在其內部建立其他物件
2. 簡單工廠模式
工廠可以幫助開發人員建立不同型別的物件,而不是直接將物件例項化
from abc import ABCMeta, abstractmethod
class Animal(metaclass=ABCMeta):
@abstractmethod
def do_say(self):
pass
class Dog(Animal):
def do_say(self):
print("Wong Wong!!")
class Cat(Animal):
def do_say(self):
print("Miao Miao!!")
## forest factory defined
class ForestFactory(object):
def make_sound(self, object_type):
return eval(object_type)().do_say()
## client code
if __name__ == '__main__':
ff = ForestFactory()
animal = input("Which animal should make_sound Dog or Cat?")
ff.make_sound(animal)
執行結果:
Which animal should make_sound Dog or Cat?Cat
Miao Miao!!
3. 工廠方法模式
工廠方法模式要點:
- 我們定義了一個介面來建立,但是工廠本身並不負責建立物件,而是將這個任務交由子類來完成,即子類決定了要例項化哪些類
- 工廠方法的建立是通過繼承而不是通過例項化來完成的
- 工廠方法使設計更加具有可定製性。它可以返回相同的例項或子類,而不是某些型別的物件(就像在簡單工廠方法中的那樣)
實現工廠方法:
假設我們想在不同型別的社交網站(例如:LinkedIn、Facebook)上為個人或公司建立簡介
那麼每個簡介都有某些特定的組成章節
LinkedIn: 個人專利或出版作品區 + 個人資訊區
Facebook: 在相簿中度假的照片區 + 個人資訊區
簡言之,我們通過將正確的區新增到相應的簡介中來建立不同型別的簡介
from abc import ABCMeta, abstractmethod
class Section(metaclass=ABCMeta):
@abstractmethod
def describe(self):
pass
class PersonalSection(Section):
def describe(self):
print("個人資訊 Section")
class AlbumSection(Section):
def describe(self):
print("相簿 Section")
class PatentSection(Section):
def describe(self):
print("專利區 Section")
class PublicationSection(Section):
def describe(self):
print("出版作品 Section")
我們建立一個Profile抽象類,提供一個工廠方法createProfile(),建立相應的簡介
工廠方法類:只提供了介面,並沒有實際建立類
子類決定使用哪些區
class Profile(metaclass=ABCMeta):
def __init__(self):
self.sections = []
self.createProfile()
@abstractmethod
def createProfile(self):
pass
def getSections(self):
return self.sections
def addSections(self, section):
self.sections.append(section)
class linkedin(Profile):
def createProfile(self):
self.addSections(PersonalSection())
self.addSections(PatentSection())
self.addSections(PublicationSection())
class facebook(Profile):
def createProfile(self):
self.addSections(PersonalSection())
self.addSections(AlbumSection())
if __name__ == "__main__":
profile_type = input("Which Profile you'd like to create? \
[LinkedIn or FaceBook]")
profile = eval(profile_type.lower())()
print("Creating Profile..", type(profile).__name__)
print("Profile has sections --", profile.getSections())
執行結果:
Which Profile you’d like to create? [LinkedIn or FaceBook]facebook
Creating Profile… facebook
Profile has sections – [<main.PersonalSection object at 0x7fb4c03bff28>,
<main.AlbumSection object at 0x7fb4c03bf780>]
可以發現:工廠方法裡面的工廠不建立類,只提供介面
facebook選定後,facebook類就被例項化,Profile中的__init__方法被呼叫,
–> __init__中的createProfile()方法被呼叫 --> addSections被呼叫,
–> Section列表的append()方法被呼叫
4. 工廠方法模式的優點
- ta具有更大的靈活性,程式碼更加通用,因為它不是單純地例項化某個類。這樣實現哪些類取決於介面
- 鬆耦合,因為建立物件的程式碼與使用它的程式碼是分開的。客戶端無需關心傳遞哪些引數以及需要例項化哪些類。由於新增新類更加容易,所以降低了維護成本
5. 抽象工廠模式
抽象工廠模式的主要目的是提供一個介面來建立一系列相關物件,而無需指定具體的類
抽象工廠的目標是建立一系列相關物件,而工廠方法模式將建立例項的任務交給了子類
實際上,抽象工廠模式不僅確保客戶端與物件的建立相互隔離,同時還確保客戶端能夠使用建立的物件
但是客戶端只能通過介面訪問物件
from abc import ABCMeta, abstractmethod
# 抽象工廠基類:pizza factory
class PizzaFactory(metaclass=ABCMeta):
@abstractmethod
def createVegPizza(self):
pass
@abstractmethod
def createNonVegPizza(self):
pass
# Indian pizza factory
class IndianPizzaFactory(PizzaFactory):
def createVegPizza(self):
return DeluxVeggiePizza()
def createNonVegPizza(self):
return ChickenPizza()
# USA pizza factory
class USPizzaFactory(PizzaFactory):
def createVegPizza(self):
return MexicanVegPizza()
def createNonVegPizza(self):
return HamPizza()
class VegPizza(metaclass=ABCMeta):
@abstractmethod
def prepare(self, VegPizza):
pass
class NonVegPizza(metaclass=ABCMeta):
@abstractmethod
def serve(self, VegPizza):
pass
class DeluxVeggiePizza(VegPizza):
def prepare(self):
print("Prepare ", type(self).__name__)
class ChickenPizza(NonVegPizza):
def serve(self, VegPizza):
print(type(self).__name__, "is served with Chicken on ", \
type(VegPizza).__name__)
class MexicanVegPizza(VegPizza):
def prepare(self):
print("Prepare ", type(self).__name__)
class HamPizza(NonVegPizza):
def serve(self, VegPizza):
print(type(self).__name__, "is served with Ham on ", \
type(VegPizza).__name__)
class PizzaStore:
def __init__(self):
pass
def makePizza(self):
for factory in [IndianPizzaFactory(), USPizzaFactory()]:
self.factory = factory
self.NonVegPizza = self.factory.createNonVegPizza()
self.VegPizza = self.factory.createVegPizza()
self.VegPizza.prepare()
self.NonVegPizza.serve(self.VegPizza)
pizza = PizzaStore()
pizza.makePizza()
執行結果:
Prepare DeluxVeggiePizza
ChickenPizza is served with Chicken on DeluxVeggiePizza
Prepare MexicanVegPizza
HamPizza is served with Ham on MexicanVegPizza
解析:
- 與工廠方法的主要區別是: 將工廠多了一層抽象,它建立的不是一個物件而是一類物件
- 本例中,當建立工廠後,會同步建立蔬菜披薩和非蔬菜披薩兩個類
6. 工廠方法與抽象工廠方法的區別
工廠方法 | 抽象工廠方法 |
---|---|
它向客戶端開放了一個建立物件的方法 | 抽象工廠包含了一個或多個工廠方法來建立一系列的相關物件 |
它使用繼承和子類來決定要建立哪個物件 | 它使用組合將建立物件的任務委託給其他類 |
工廠方法用於建立一個產品 | 抽象工廠用於建立相關產品系列 |
7. 小結
1、介紹了工廠設計模式及其使用的上下文; 如何在軟體架構有效使用工廠模式
2、簡單工廠模式:可以執行時根據客戶端傳入的引數型別來建立相應的例項
3、工廠方法模式:定義一個介面建立物件,但是物件的例項化交給子類
4、抽象工廠模式:提供介面,無需指定具體的類就能建立一系列的相關物件
5、Python實現3種工廠模式,並比較了工廠方法與抽象工廠方法的區別