意图
抽象工厂 是一种创建设计模式,它允许我们生成相关对象的系列,而无需指定它们的具体类。 这意味着抽象工厂允许一个类返回一个类工厂,因此,抽象工厂被认为比工厂方法设计模式高一级。
问题
假设您正在开发像 Pepperfry 这样的家具电子商务网站,该网站销售椅子、桌子和沙发,既可以单独销售,也可以组合销售。 椅子、桌子和沙发有不同的变体,例如 维多利亚时代 和 现代的. 现在对于维多利亚变体,您的代码需要实现不同的类,如 VictorianChair、VictorianTable、VictorianSofa,对于现代变体也是如此。
到目前为止,这似乎很好,但是如果您想添加更多家具系列变体,例如 当代的, 传统的, 等等,那么您必须实现它们相应的家具类,并且必须修改大部分现有代码以支持这些变体。 越来越多的家具类也使您的代码非常冗长和混乱。 此外,当客户收到不匹配的家具时,他们会非常生气。
解决方案
根据
抽象工厂
设计模式 –
- 您需要为椅子、沙发和桌子等单个产品声明接口或抽象类。 通过实现这些接口(或扩展这些抽象类),您可以制作产品的所有变体。 例如,扩展椅子抽象类,您可以制作 Victorian Chair、ModernChair 等。
- 现在,对于产品系列的每个变体,您需要基于 AbstractFactory 接口或抽象类创建一个单独的工厂类。 工厂是返回特定种类产品的类。 例如,VictorianFurnitureFactory 只能创建 VictorianChair、VictorianSofa 和 VictorianTable 对象。
客户端代码通过其相应的抽象类或接口暴露给产品和工厂。 这使您能够更改传递给客户端代码的工厂类型以及客户端代码接收的产品变体,而不会破坏实际的客户端代码。
代码
import abc from enum import Enum class FurnitureComboType(Enum): VICTORIAN = 0 MODERN = 1 class Chair: @abc.abstractmethod def hasLegs(self) -> bool: pass @abc.abstractmethod def hasSeatCushion(self) -> bool: pass @abc.abstractmethod def hasBackCushion(self) -> bool: pass @abc.abstractmethod def getMaterialType(self) -> str: pass class Sofa: @abc.abstractmethod def getNumberOfSeats(self) -> int: pass @abc.abstractmethod def canBeConvertedToBed(self) -> bool: pass @abc.abstractmethod def canBeFolded(self) -> bool: pass @abc.abstractmethod def getMaterialType(self) -> str: pass class Table: @abc.abstractmethod def getWidth(self) -> float: pass @abc.abstractmethod def getHeight(self) -> float: pass @abc.abstractmethod def getTopMaterialType(self) -> str: pass @abc.abstractmethod def getBaseMaterialType(self) -> str: pass class VictorianChair(Chair): def hasLegs(self) -> bool: return True def hasSeatCushion(self) -> bool: return True def hasBackCushion(self) -> bool: return True def getMaterialType(self) -> str: return "Polished Mahogany Wood" class VictorianSofa(Sofa): def getNumberOfSeats(self) -> int: return 3 def canBeConvertedToBed(self) -> bool: return False def canBeFolded(self) -> bool: return False def getMaterialType(self) -> str: return "Polished Mahogany Wood" class VictorianTable(Table): def getWidth(self) -> float: return 2 def getHeight(self) -> float: return 3 def getTopMaterialType(self) -> str: return "Polished Mahogany Wood" def getBaseMaterialType(self) -> str: return "Polished Mahogany Wood" class ModernChair(Chair): def hasLegs(self) -> bool: return False def hasSeatCushion(self) -> bool: return True def hasBackCushion(self) -> bool: return True def getMaterialType(self) -> str: return "Vinyl" class ModernSofa(Sofa): def getNumberOfSeats(self) -> int: return 2 def canBeConvertedToBed(self) -> bool: return True def canBeFolded(self) -> bool: return True def getMaterialType(self) -> str: return "Leather" class ModernTable(Table): def getWidth(self) -> float: return 3 def getHeight(self) -> float: return 4 def getTopMaterialType(self) -> str: return "Glass" def getBaseMaterialType(self) -> str: return "Solid Wood" class FurnitureFactory: @abc.abstractmethod def getChair(self) -> Chair: pass @abc.abstractmethod def getSofa(self) -> Sofa: pass @abc.abstractmethod def getTable(self) -> Table: pass class VictorianFurnitureFactory(FurnitureFactory): def __init__(self) -> None: self._chair = VictorianChair() self._sofa = VictorianSofa() self._table = VictorianTable() def getChair(self) -> Chair: return self._chair def getSofa(self) -> Sofa: return self._sofa def getTable(self) -> Table: return self._table class ModernFurnitureFactory(FurnitureFactory): def __init__(self) -> None: self._chair = ModernChair() self._sofa = ModernSofa() self._table = ModernTable() def getChair(self) -> Chair: return self._chair def getSofa(self) -> Sofa: return self._sofa def getTable(self) -> Table: return self._table class FurnitureFactoryCreator: def getFurnitureCombo(self, requestedComboType: FurnitureComboType) -> FurnitureFactory: if requestedComboType == FurnitureComboType.VICTORIAN: return VictorianFurnitureFactory() elif requestedComboType == FurnitureComboType.MODERN: return ModernFurnitureFactory() else: return None if __name__ == "__main__": furnitureCombo = FurnitureFactoryCreator().getFurnitureCombo(FurnitureComboType.VICTORIAN) chair = furnitureCombo.getChair() sofa = furnitureCombo.getSofa() table = furnitureCombo.getTable() print(f"Chair Material Type: {chair.getMaterialType()}") print(f"Number of Sofa seats: {sofa.getNumberOfSeats()}") print(f"Table top Material Type: {table.getTopMaterialType()}") Output
适用性
使用 抽象工厂 当您的代码需要与各种相关产品系列一起工作,但这些产品的具体类可能事先未知,或者您只是希望您的代码在未来可扩展时,设计模式。
优点和缺点
优点 | 缺点 |
它将混凝土产品解耦。 从客户端代码。 | 它引入了许多新的抽象类或接口来实现这种增加了复杂性的模式。 |
它确保从工厂获得的产品相互兼容。 | |
它遵循单一职责原则。 它将产品创建代码移动到程序中的一个位置,从而更容易支持代码。 | |
它遵循开放/封闭原则。 您可以轻松地将应用程序扩展为新的产品变体,而无需破坏现有代码。 |
这 抽象工厂 设计模式还可用于创建跨平台 UI,无需将客户端代码耦合到具体的 UI 类,并使所有创建的视图与不同的操作系统保持一致。 这将在以后的文章中介绍。 在那之前,快乐编码!