用Python實現設計模式——工廠模式

前言

工廠模式,顧名思義就是咱們能夠經過一個指定的「工廠」得到須要的「產品」,在設計模式中主要用於抽象對象的建立過程,讓用戶能夠指定本身想要的對象而沒必要關心對象的實例化過程。這樣作的好處是用戶只需經過固定的接口而不是直接去調用類的實例化方法來得到一個對象的實例,隱藏了實例建立過程的複雜度,解耦了生產實例和使用實例的代碼,下降了維護的複雜性。
本文會用Python實現三種工廠模式的簡單例子,全部代碼都託管在Github上。html

簡單工廠

首先,咱們先看一個簡單工廠的例子:python

#coding=utf-8
class Mercedes(object):
    """梅賽德斯
    """
    def __repr__(self):
        return "Mercedes-Benz"

class BMW(object):
    """寶馬
    """
    def __repr__(self):
        return "BMW"

假設咱們有兩個「產品」分別是MercedesBMW的汽車,若是沒有「工廠」來生產它們,咱們就要在代碼中本身進行實例化,如:git

mercedes = Mercedes()
bmw = BMW()

但現實中,你可能會面對不少汽車產品,並且每一個產品的構造參數還不同,這樣在建立實例時會遇到麻煩。這時就能夠構造一個「簡單工廠」把全部汽車實例化的過程封裝在裏面。github

class SimpleCarFactory(object):
    """簡單工廠
    """
    @staticmethod
    def product_car(name):
        if name == 'mb':
            return Mercedes()
        elif name == 'bmw':
            return BMW()

有了SimpleCarFactory類後,就能夠經過向固定的接口傳入參數得到想要的對象實例,以下:數據庫

c1 = SimpleCarFactory.product_car('mb')
c2 = SimpleCarFactory.product_car('bmw')

工廠方法

雖然有了一個簡單的工廠,但在實際使用工廠的過程當中,咱們會發現新問題:若是咱們要新增一個「產品」,例如Audi的汽車,咱們除了新增一個Audi類外還要修改SimpleCarFactory內的product_car方法。這樣就違背了軟件設計中的開閉原則[1],即在擴展新的類時,儘可能不要修改原有代碼。因此咱們在簡單工廠的基礎上把SimpleCarFactory抽象成不一樣的工廠,每一個工廠對應生成本身的產品,這就是工廠方法。設計模式

#coding=utf-8
import abc

class AbstractFactory(object):
    """抽象工廠
    """
    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    def product_car(self):
        pass

class MercedesFactory(AbstractFactory):
    """梅賽德斯工廠
    """
    def product_car(self):
        return Mercedes()

class BMWFactory(AbstractFactory):
    """寶馬工廠
    """
    def product_car(self):
        return BMW()

咱們把工廠抽象出來用abc模塊[2]實現了一個抽象的基類AbstractFactory,這樣就能夠經過特定的工廠來得到特定的產品實例了:網絡

c1 = MercedesFactory().product_car()
c2 = BMWFactory().product_car()

每一個工廠負責生產本身的產品也避免了咱們在新增產品時須要修改工廠的代碼,而只要增長相應的工廠便可。如新增一個Audi產品,只需新增一個Audi類和AudiFactory類。字體

抽象工廠

工廠方法雖然解決了咱們「修改代碼」的問題,但若是咱們要生產不少產品,就會發現咱們一樣須要寫不少對應的工廠類。好比若是MercedesFactoryBMWFactory不只生產小汽車,還要生產SUV,那咱們用工廠方法就要再多構造兩個生產SUV的工廠類。因此爲了解決這個問題,咱們就要再更進一步的抽象工廠類,讓一個工廠能夠生產同一類的多個產品,這就是抽象工廠。具體實現以下:設計

#coding=utf-8
import abc

# 兩種小汽車
class Mercedes_C63(object):
    """梅賽德斯 C63
    """
    def __repr__(self):
        return "Mercedes-Benz: C63"

class BMW_M3(object):
    """寶馬 M3
    """
    def __repr__(self):
        return "BMW: M3"

# 兩種SUV
class Mercedes_G63(object):
    """梅賽德斯 G63
    """
    def __repr__(self):
        return "Mercedes-Benz: G63"

class BMW_X5(object):
    """寶馬 X5
    """
    def __repr__(self):
        return "BMW: X5"

class AbstractFactory(object):
    """抽象工廠
    能夠生產小汽車外,還能夠生產SUV
    """
    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    def product_car(self):
        pass

    @abc.abstractmethod
    def product_suv(self):
        pass

class MercedesFactory(AbstractFactory):
    """梅賽德斯工廠
    """
    def product_car(self):
        return Mercedes_C63()

    def product_suv(self):
        return Mercedes_G63()

class BMWFactory(AbstractFactory):
    """寶馬工廠
    """
    def product_car(self):
        return BMW_M3()

    def product_suv(self):
        return BMW_X5()

咱們讓基類AbstractFactory同時能夠生產汽車和SUV,而後令MercedesFactoryBMWFactory繼承AbstractFactory並重寫product_car和product_suv方法便可。日誌

c1 = MercedesFactory().product_car()
s1 = MercedesFactory().product_suv()
print(c1, s1)
s2 = BMWFactory().product_suv()
c2 = BMWFactory().product_car()
print(c2, s2)

抽象工廠模式與工廠方法模式最大的區別在於,抽象工廠中的一個工廠對象能夠負責多個不一樣產品對象的建立 ,這樣比工廠方法模式更爲簡單、有效率。

結論

初學設計模式時會對三種工廠模式的實際應用比較困惑,其實三種模式各有優缺點,應用的場景也不盡相同:

  • 簡單工廠模式適用於需建立的對象較少,不會形成工廠方法中的業務邏輯太過複雜的狀況下,並且用戶只關心那種類型的實例被建立,並不關心其初始化過程時,好比多種數據庫(MySQL/MongoDB)的實例,多種格式文件的解析器(XML/JSON)等。
  • 工廠方法模式繼承了簡單工廠模式的優勢又有所改進,其再也不經過一個工廠類來負責全部產品的建立,而是將具體建立工做交給相應的子類去作,這使得工廠方法模式能夠容許系統可以更高效的擴展。實際應用中能夠用來實現系統的日誌系統等,好比具體的程序運行日誌,網絡日誌,數據庫日誌等均可以用具體的工廠類來建立。
  • 抽象工廠模式在工廠方法基礎上擴展了工廠對多個產品建立的支持,更適合一些大型系統,好比系統中有多於一個的產品族,且這些產品族類的產品需實現一樣的接口,像不少軟件系統界面中不一樣主題下不一樣的按鈕、文本框、字體等等。

參考

[1]維基百科
[2]Python官方文檔


2018/1/30更新:修改工廠方法的代碼示例,新增結論一節。

相關文章
相關標籤/搜索