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)
相关文章
相关标签/搜索