抽象工厂——Python中的设计模式

意图

抽象工厂 是一种创建设计模式,它允许我们生成相关对象的系列,而无需指定它们的具体类。 这意味着抽象工厂允许一个类返回一个类工厂,因此,抽象工厂被认为比工厂方法设计模式高一个级别。

问题

假设您正在开发像 Pepperfry 这样的家具电子商务网站,该网站销售椅子、桌子和沙发,既可以单独销售,也可以组合销售。 椅子、桌子和沙发有不同的变体,例如 维多利亚时代现代的. 现在对于维多利亚变体,您的代码需要实现不同的类,如 VictorianChair、VictorianTable、VictorianSofa,对于现代变体也是如此。

到目前为止,这似乎很好,但是如果您想添加更多家具系列变体,例如 当代的, 传统的, 等等,那么您必须实现它们相应的家具类,并且必须修改大部分现有代码以支持这些变体。 越来越多的家具类也使您的代码非常冗长和混乱。 此外,当客户收到不匹配的家具时,他们会非常生气。

解决方案

根据 抽象工厂 设计模式 –

  1. 您需要为椅子、沙发和桌子等单个产品声明接口或抽象类。 通过实现这些接口(或扩展这些抽象类),您可以制作产品的所有变体。 为了 example,扩展椅子抽象类,您可以制作维多利亚椅子、现代椅子等。
  2. 现在,对于产品系列的每个变体,您需要基于 AbstractFactory 接口或抽象类创建一个单独的工厂类。 工厂是返回特定种类产品的类。 为了 exampleVictorianFurnitureFactory 只能创建 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 类,并使所有创建的视图与不同的操作系统保持一致。 这将在以后的文章中介绍。 在那之前,快乐编码!