設計模式Design Pattern - Abstract Factory

Jimmy Huang
6 min readAug 26, 2020

--

最近試著讀Design pattern, 不過有些概念實在太抽象了, 整理一下自己所學
抽象工廠的精神,就是要有abstract class(not implement),而所有不同種類的物件,都是繼承這個abstract class
但是使用者只知道interface的接口就好

很抽象吧,直接舉例會比較實在,今天我開發了一個Qt windows app,Qt是跨平台的框架,所以Qt假設裡面有個button class

class Button:
def clicked():
print(clicked)

這個Button絕對不會這麼簡單,他還要跟不同作業系統兼容,所以就會有mac的button,windows的button,我們就可以先開個抽象類

class Button(ABC):
@abstractmethod
def clicked(self):
pass

class WinButton(Button):
def clicked(self):
print('click winbutton')

class MacButton(Button):
def clicked(self):
print('click macbutton')

qt的interface可是非常多物件的,有button還有checkbox等等,這樣我寫程式的時候就要打self.btn = WinButton()這樣子???,然後今天要打包到Mac上,又要改成self.btn = MacButton(),這樣子是非常沒有效率的...,能不能把這個作業系統的環境提取出來呢???

白話就是,我們需要一個工廠,這個工廠可以幫我們呼叫下面不同的控件,例如WinFactory就是要給我windows的控件

class GUIFactory(ABC):
@abstractmethod
def create_button(self):
pass
@abstractmethod
def create_checkbox(self):
pass
class WinFactory(GUIFactory):
def create_button(self):
return WinButton()
def create_checkbox(self):
return WinCheckBox()
class MacFactory(GUIFactory):
def create_button(self):
return MacButton()
def create_checkbox(self):
return MacCheckBox()

換個譬喻,你今天要吃大餐,而有前菜,主餐,甜點,而大餐有不同風格,
你不會想要這樣說: 主廚我要日式前菜,日式主餐,日式甜點
而是會想要這樣說: 日式主廚,我要前菜、主餐、甜點
這邊的日式主廚就是工廠啦!!
主廚要會煮菜 上菜 切菜 等 這個就是抽象工廠,而日式主廚,西式主廚,就是工廠

那這樣來看看前面的關係圖怎麼畫

資料來源: https://refactoringguru.cn/design-patterns/abstract-factory

完整程式碼

from abc import ABC, abstractmethodclass GUIFactory(ABC):
@abstractmethod
def create_button(self):
pass
@abstractmethod
def create_checkbox(self):
pass
class WinFactory(GUIFactory):
def create_button(self):
return WinButton()
def create_checkbox(self):
return WinCheckBox()
class MacFactory(GUIFactory):
def create_button(self):
return MacButton()
def create_checkbox(self):
return MacCheckBox()
class Button(ABC):
@abstractmethod
def clicked(self):
pass

class WinButton(Button):
def clicked(self):
print('click winbutton')

class MacButton(Button):
def clicked(self):
print('click macbutton')
class CheckBox(ABC):
@abstractmethod
def checked(self):
pass

class WinCheckBox(CheckBox):
def checked(self):
print('check wincheckbox')
class MacCheckBox(CheckBox):
def checked(self):
print('check maccheckbox')
class Application:
def __init__(self, factory):
self.button = factory.create_button()
self.checkbox = factory.create_checkbox()

if __name__ == "__main__":
app = Application(MacFactory())
app.button.clicked()

注意,這樣子,對使用者而言,就是Application最後call的時候傳入引數(Mac or Win Factory),這邊甚至能加個if else直接判斷當前os
最後那個對使用者而言 看到的都是app
app.button, app.checkbox, 早就已經透過工廠創造好啦

總結:
抽象工廠模式: 對使用者來說單一接口,所有class需要繼承abstract class

抽象工廠為你提供了一個接口, 可用於創建每個系列產品的對象。 只要代碼通過該接口創建對象, 那麼你就不會生成與應用程序已生成的產品類型不一致的產品

--

--