Neil 啃設計模式(0x3)抽象工廠模式

抽象工廠模式(Abstract Factory Pattern)

定義

Provide an interface for creating families of related or dependent objects without specifying their concrete classes.(爲建立一組相關或相互依賴的對象提供一個接口,並且無須指定它們的具體類。)
《設計模式之禪》

我的理解抽象工廠模式與工廠模式的最大區別在於定義中的關鍵詞 一組相關或者相互依賴的對象。例如,咱們要生產一輛汽車,那麼汽車的各個必要組件就是一組相關的或相互依賴的對象,每一個組件就是一個產品對象,而組合在一塊兒就是一個產品族,一輛汽車的三大件(發動機+底盤+變速箱)。每一個種型號的汽車都要有這一系列的產品族。只是所用的型號不一樣罷了。
那麼,咱們每一個型號的汽車就是一個工廠,都繼承了一個抽象工廠,抽象工廠負責定義產品族中每一個產品的製造。
固然,每一個產品有本身的屬性,且可以創造出不一樣的型號。python

UML 示例

@startuml
Interface Engine
Interface Underpan
Interface Gearbox
Interface abstractFactory

class EngineA
Engine <-- EngineA
class EngineB
Engine <-- EngineB

class UnderpanA
Underpan <-- UnderpanA
class UnderpanB
Underpan <-- UnderpanB

class GearboxA
Gearbox <-- GearboxA
class GearboxB
Gearbox <-- GearboxB

class FactoryA{
    +createEngine()
    +createUnderpan()
    +createGearbox()
}
abstractFactory <-- FactoryA
class FactoryB{
    +createEngine()
    +createUnderpan()
    +createGearbox()
}

abstractFactory <-- FactoryB

FactoryA ..>EngineA
FactoryA ..>UnderpanA
FactoryA ..>GearboxA

FactoryB ..>EngineB
FactoryB ..>UnderpanB
FactoryB ..>GearboxB
@enduml

解釋: Engine 發動機,Underpan 底盤和 Gearbox 變速箱共同組成了一個產品族
A、B 分別表示兩種車的型號git

代碼實現

仍是要強調一點,python 中代碼實現是能夠棄用接口實現類的,因此,咱們的代碼中,關於 Engine、Underpan、Gearbox、AbstractFactory 的接口定義就不寫了編程

# 型號A的汽車組件
class EngineA:
    def get_engin(self):
        print("A: Engine")


class UnderpanA:
    def get_underpan(self):
        print("A: Underpan")


class GearboxA:
    def get_gearbox(self):
        print("A: GerboxA")


# 型號B的汽車組件
class EngineB:
    def get_engin(self):
        print("B: Engine")


class UnderpanB:
    def get_underpan(self):
        print("B: Underpan")


class GearboxB:
    def get_gearbox(self):
        print("B: GerboxA")


# factory A
class FactoryA:
    def create_engine(self):
        return EngineA()

    def create_underpan(self):
        return UnderpanA()

    def create_gearbox(self):
        return GearboxA()


class FactoryB:
    def create_engine(self):
        return EngineB()

    def create_underpan(self):
        return UnderpanB()

    def create_gearbox(self):
        return GearboxB()


if __name__ == "__main__":
    productA = FactoryA()
    productB = FactoryB()
    productA.create_engine().get_engin()
    productA.create_gearbox().get_gearbox()
    productA.create_underpan().get_underpan()

    productB.create_engine().get_engin()
    productB.create_gearbox().get_gearbox()
    productB.create_underpan().get_underpan()

應用場景

  1. 不適用與產品族這種縱向擴展需求,即一臺汽車就這些組件,產品族中不增長組件,由於若是產品族中增減組件,那麼全部的汽車型號都要擴展,因此是縱向擴展能力不強。
  2. 適用於橫向產品擴展,好比:增長一個新的汽車類型 C,那麼只須要新增一個 C 產品文件,實現響應的產品族接口和工廠便可
  3. 具體舉例:咱們系統中對時間的格式化,對貨幣形式的格式化,每一個國家可能不一樣。貨幣+時間格式化組成產品族,而能夠橫向擴展不一樣的國家 Chain,USA...
  4. 我的理解產品族是一個不常常變的東西,因此放在一塊兒用一個工廠類給包裝起來
《python 面向對象編程》中的例子
class FranceDateFormatter:
    def format_date(self, y, m, d):
        y, m, d = (str(x) for x in (y, m, d))
        y = '20' + y if len(y) == 2 else y
        m = '0' + m if len(m) == 1 else m
        d = '0' + d if len(d) == 1 else d
        return ("{0}/{1}/{2}".format(d, m, y))


class USADateFormatter:
    def format_date(self, y, m, d):
        y, m, d = (str(x) for x in (y, m, d))
        y = '20' + y if len(y) == 2 else y
        m = '0' + m if len(m) == 1 else m
        d = '0' + d if len(d) == 1 else d
        return ("{0}-{1}-{2}".format(m, d, y))


class FranceCurrencyFormatter:
    def format_currency(self, base, cents):
        base, cents = (str(x) for x in (base, cents))
        if len(cents) == 0:
            cents = '00'
        elif len(cents) == 1:
            cents = '0' + cents

        digits = []
        for i, c in enumerate(reversed(base)):
            if i and not i % 3:
                digits.append(' ')
            digits.append(c)
        base = ''.join(reversed(digits))
        return "{0} {1}".format(base, cents)


class USACurrencyFormatter:
    def format_currency(self, base, cents):
        base, cents = (str(x) for x in (base, cents))
        if len(cents) == 0:
            cents = '00'
        elif len(cents) == 1:
            cents = '0' + cents

        digits = []
        for i, c in enumerate(reversed(base)):
            if i and not i % 3:
                digits.append(',')
            digits.append(c)
        base = ''.join(reversed(digits))
        return "{0} {1}".format(base, cents)


class USAFormatterFactory:
    def create_date_formatter(self):
        return USADateFormatter()

    def create_currency_formatter(self):
        return USACurrencyFormatter()


class FranceFormatterFactory:
    def create_date_formatter(self):
        return FranceDateFormatter()

    def create_currency_formatter(self):
        return FranceFormatterFactory()


country_code = "US"
factory_map = {
    "US": USAFormatterFactory,
    "FR": FranceFormatterFactory
}

formatter_factory = factory_map.get(country_code)
相關文章
相關標籤/搜索