Python实现软件设计模式3:抽象工厂模式

发布时间 2023-12-17 10:42:12作者: 爱吃砂糖橘的白龙

特点

  • 系统中除了有多种产品类型(产品等级结构,如果汁、方便面、矿泉水),还出现了多个品牌(产品族,或农夫山泉、娃哈哈、康师傅、统一等品牌几乎都有这些产品)
  • 在工厂方法模式中,只有一个产品等级结构
  • 一个抽象产品(父类)、多个具体产品(子类)形成一个产品等级结构
  • 产品族是指由同一个工厂生产,位于不同产品等级结构的一组产品

角色组成

  • 抽象工厂 Abstract Factory
  • 具体工厂 Concrete Factory
  • 抽象产品 Abstract Product
  • 具体产品 Concrete Product

模式实例

电器工厂:一个电器工厂可以生产多种类型的电器,如海尔工厂可以生产海尔电视机、海尔空调等,TCL工厂可以生产TCL电视机、TCL空调等,相同品牌的电器构成一个产品族,而向同类型的电器构成了一个产品等级结构。

代码实现

from abc import ABC,abstractmethod

class TV(ABC):      # 抽象产品 1
    @abstractmethod
    def play(self):
        pass

class AirConditioner(ABC):  # 抽象产品 2
    @abstractmethod
    def changetemperature(self):
        pass

class HaierTV(TV):  # 具体产品
    def play(self):
        print("海尔电视播放中...")

class HuaweiTV(TV): # 具体产品
    def play(self):
        print("华为电视播放中...")

class HaierAirCon(AirConditioner):  # 具体产品
    def changetemperature(self):
        print("海尔空调温度改变中!!!")

class HuaweiAirCon(AirConditioner): # 具体产品
    def changetemperature(self):
        print("华为空调温度改变中!!!")

class EFactory(ABC):    # 抽象工厂
    @abstractmethod
    def produceTV(self):
        pass
    
    @abstractmethod
    def produceAirCon(self):
        pass

class HaierFactory(EFactory):   # 具体产品族工厂1
    def produceTV(self):
        return HaierTV()
    
    def produceAirCon(self):
        return HaierAirCon()

class HuaweiFactory(EFactory):  # 具体产品族工厂2
    def produceTV(self):
        return HuaweiTV()
    
    def produceAirCon(self):
        return HuaweiAirCon()

class Client:                   # 客户端
    def __init__(self, FactoryName):    # 传入工厂名称参数
        self.factname = FactoryName

    def run(self):
        try:
            factory = eval(self.factname)()
            tv = factory.produceTV()
            tv.play()

            ac = factory.produceAirCon()
            ac.changetemperature()
        except NameError:
            print(f"Error! Factory '{self.factname}' doesn't exits...")

if __name__ == '__main__':
    f1 = Client('HuaweiFactory')
    f1.run()

    f2 = Client('HaierFactory')
    f2.run()

总结

  • 客户端始终只使用同一个产品族中的对象
  • 增加新的产品族(品牌)很方便,无序修改已有系统源码,只需要新增已有抽象工厂的子类并在其中实现产品构造方法,符合开闭原则!
  • 增加新的产品等级结构较麻烦,因为需要修改原有系统代码(所有工厂类,包括抽象工厂和具体品牌工厂),违背了开闭原则!
  • 适合使用场景:一个系统不应该依赖于产品类实例如何被创建、组合和表达的细节