一、介紹
工廠模式(Factory Pattern)是最常用的設計模式之一,這種類型的設計模式屬於創建型模式,它提供了一種創建對象的最佳方式。
在工廠模式中,我們在創建對象時不會對客戶端暴露創建邏輯,並且是通過使用一個共同的接口來指向新創建的對象。
意圖:定義一個創建對象的接口,讓其子類自己決定實例化哪一個工廠類,工廠模式使其創建過程延遲到子類進行。
主要解決:主要解決接口選擇的問題。
何時使用:我們明確地計划不同條件下創建不同實例時。
二、簡單工廠
統一使用一個類作為對外接口,根據參數的不同,去選擇實例化不同的類。
""" 兩個產品(兩種類型的書) """ class TechnicalBooks(object): """技術書籍""" def publish(self): return "Python-Book" class LiteraryBooks(object): """文學書籍""" def publish(self): return "Black Hole Book" # 現在我們有兩種類型的書,分別是TechnicalBooks和LiteraryBooks的書 # 按照我們平常的方法來實例化的話,此時創建對象時是會對客戶端暴露真正創建的類 it_books = TechnicalBooks() ly_books = LiteraryBooks() # 這時我們就可以構造一個"簡單工廠"把所有實例化的過程封裝在里面,把真正實例的類隱藏起來 class SimpleFactory(object): """簡單工廠""" @staticmethod def publish_book(name): if name == 'technical': return TechnicalBooks() elif name == 'literary': return LiteraryBooks() it_books2 = SimpleFactory.publish_book('technical') ly_books2 = SimpleFactory.publish_book('literary')
簡單工廠的好處在於,把不同類的實例化統一到一個"工廠",即不對外暴露真正的創建類,也提供了一個對外的統一接口。
但是簡單工廠也有一個缺點,那就是違背了solid的 "開閉原則",假如我們還需要增加一種書籍,那就必須要對簡單工廠SimpleFactory進行源碼的修改,
簡單工廠使用場景:
- 已經確定有多少具體的類,不會再增加的情況下使用。
例如:某個系統,已經明確就只會有MySQL、Redis、MongoDB三個數據庫的情況下,可以直接使用簡單工廠模式。
三、工廠方法
上面的簡單工廠我們已經知道了,如果新增一些類型的時候會違背軟件設計中的開閉原則,但是我們希望在擴展新的類時,不要修改原有的代碼。這個時候我們可以在簡單工廠的基礎上把SimpleFactory抽象成不同的工廠,每個工廠對應生成自己的產品,這就是工廠方法。
""" 兩個產品(兩種類型的書) """ import abc # 真正進行實例化的類 class TechnicalBooks(object): """技術書籍""" def publish(self): return "Python-Book" class LiteraryBooks(object): """文學書籍""" def publish(self): return "Black Hole Book" # 抽象工廠:先定義抽象類,然后每種類型的書籍都有自己對於的工廠 class AbstractFactory(metaclass=abc.ABCMeta): """抽象工廠""" @abc.abstractmethod def publish_book(self): pass class TechnicalFactory(AbstractFactory): """技術書籍工廠""" def publish_book(self): return TechnicalBooks() class LiteraryFactory(AbstractFactory): """文學書籍工廠""" def publish_book(self): return LiteraryBooks() it_books2 = TechnicalFactory().publish_book() ly_books2 = LiteraryFactory().publish_book()
這樣每個工廠就只負責生產自己的產品,避免了在新增產品時需要修改工廠的代碼,遵循了"開閉原則",如果需要新增產品時,只需要增加相應的工廠即可。
比如要新增一種小說類型的書籍,只需新增一個NovelBooks類和NovelFactory類。
工廠方法的使用場景:
- 當系統中擁有的子類很多,並且以后可能還需要不斷拓展增加不同的子類時。
- 當設計系統時,還不能明確具體有哪些類時。
在工廠方法中,使用者不需要知道具體的產品類名,只需要知道其對應的工廠即可。
四、抽象工廠
工廠方法解決了"開閉原則"的問題,但是我們出版書籍之前肯定還會有其他的步驟,比如印刷。
如果每一個步驟我們就要寫一個對應的工廠類,那我們就會需要創建很多很多類了。
因此為了解決這個問題,我們就要需要抽象工廠類,讓一個工廠可以生產同一類的多個產品或多個動作(步驟),這就是抽象工廠。
""" 兩個產品(兩種類型的書) """ import abc # 印刷書籍 class PrintingTechnicalBooks(object): """印刷技術書籍""" def printing(self): return "Print-Python-Book" class PrintingLiteraryBooks(object): """印刷文學書籍""" def printing(self): return "Print Black Hole Book" # 出版書籍 class TechnicalBooks(object): """出版技術書籍""" def publish(self): return "Python-Book" class LiteraryBooks(object): """出版文學書籍""" def publish(self): return "Black Hole Book" # 抽象工廠:先定義抽象類,然后每種類型的書籍都有自己對於的工廠 class AbstractFactory(metaclass=abc.ABCMeta): """抽象工廠""" @abc.abstractmethod def print_book(self): pass @abc.abstractmethod def publish_book(self): pass class TechnicalFactory(AbstractFactory): """技術書籍工廠""" def print_book(self): return PrintingTechnicalBooks() def publish_book(self): return TechnicalBooks() class LiteraryFactory(AbstractFactory): """文學書籍工廠""" def print_book(self): return PrintingLiteraryBooks() def publish_book(self): return LiteraryBooks() # 實例化工廠對象 it = TechnicalFactory() ly = LiteraryFactory() # 印刷書籍 it_print = it.print_book() ly_print = ly.print_book() # 出版書籍 it_publish = it.publish_book() ly_publish = ly.publish_book()
抽象工廠模式與工廠方法模式的區別:
抽象工廠中的一個工廠對象可以負責多個不同產品對象的創建
抽象工廠的使用場景:
- 當多個產品(步驟)集合在一起,組成產品族時。
- 對於一個產品族,如果只想顯示接口而不是實現時。