当前位置: 首页 > 后端技术 > Python

尼尔啃设计模式(0x3)抽象工厂模式

时间:2023-03-25 22:24:55 Python

抽象工厂模式(AbstractFactoryPattern)定义提供一个接口,用于创建相关或依赖对象的族,而无需指定它们的具体类。(为创建一组相关或相互依赖的对象提供接口,而不指定它们具体的类。)《设计模式之禅》个人理解抽象工厂模式与工厂模式最大的区别在于定义中的关键字是一组相关或相互依赖的对象。例如,如果我们要生产一辆汽车,汽车的每个必要部件都是一组相关或相互依赖的对象,每个部件都是一个产品对象,组合起来就是一个产品系列,汽车的三个主要部分(发动机+底盘+变速箱)。每一款车型都必须有这个系列的产品系列。只是使用的型号不同。那么,我们汽车的每个车型都是一个工厂,继承了一个抽象工厂,负责定义产品族中每个产品的制造。当然,每个产品都有自己的属性,可以打造出不同的造型。UML示例@startumlInterfaceEngineInterfaceUnderpanInterfaceGearboxInterfaceabstractFactoryclassEngineAEngine<--EngineAclassEngineBEngine<--EngineBclassUnderpanAUnderpan<--UnderpanAclassUnderpanBUnderpan<--UnderpanBclassGearboxAGearbox<--GearboxAclassGearboxBGearbox<--GearboxBclassFactoryA{+createEngine()+createUnderpan()+createGearbox()}abstractFactory<--FactoryAclassFactoryB{+createEngine()+createUnderpan()+createGearbox()}abstractFactory<--FactoryBFactoryA..>EngineAFactoryA..>UnderpanAFactoryA..>GearboxAFactoryB..>EngineBFactoryB..>UnderpanBFactoryB..>GearboxB@enduml解释:Engine、Underpan底盘和Gearbox变速箱共同组成一个产品系列A和B,分别代表两款车的型号代码实现。需要强调的是,python中的代码实现可以放弃接口实现类,所以,在我们的代码中,Engine、Underpan、Gearbox、AbstractFactory的接口定义都没有写#ModelAcarcomponentclassEngineA:defget_engin(self):print("A:Engine")classUnderpanA:defget_underpan(self):print("A:Underpan")classGearboxA:defget_gearbox(self):print("A:GerboxA")#型号B的汽车组件classEngineB:defget_engin(self):print("B:Engine")classUnderpanB:defget_underpan(self):print("B:Underpan")classGearboxB:defget_gearbox(self):print("B:GerboxA")#factoryAclassFactoryA:defcreate_engine(self):returnEngineA()defcreate_underpan(自我):返回UnderpanA()defcreate_gearbox(self):返回GearboxA()classFactoryB:defcreate_engine(self):返回EngineB()defcreate_underpan(self):返回UnderpanB()defcreate_gearbox(self):返回GearboxB()如果__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()产品ctB.create_underpan().get_underpan()应用场景不适用于产品族的垂直扩展需求,即一辆汽车只有这些组件,没有组件添加到产品族中,因为如果添加组件或者从产品族中剔除,那么所有车型都要扩容,所以垂直扩容能力不强。适合横向产品拓展。比如新增一款车型C,只需要添加一个C产品文件,实现对应的产品族接口和工厂即可。具体示例:我们系统中时间和货币的格式可能因国家/地区而异。Currency+timeformatting组成一个productfamily,可以横向扩展到不同的国家Chain,USA...:defformat_date(self,y,m,d):y,m,d=(str(x)forxin(y,m,d))y='20'+yiflen(y)==2elseym='0'+miflen(m)==1elsemd='0'+diflen(d)==1elsedreturn("{0}/{1}/{2}".format(d,m,y))类USADateFormatter:defformat_date(self,y,m,d):y,m,d=(str(x)forxin(y,m,d))y='20'+yiflen(y)==2elseym='0'+miflen(m)==1elsemd='0'+diflen(d)==1elsedreturn("{0}-{1}-{2}".format(m,d,y))classFranceCurrencyFormatter:defformat_currency(self,base,cents):base,cents=(str(x)forxin(base,cents))iflen(cents)==0:cents='00'eliflen(cents)==1:cents='0'+centsdigits=[]fori,cinenumerate(reversed(base)):ifi而不是我3:digits.append('')digits.append(c)base=''.join(reversed(digits))返回“{0}{1}”.format(base,cents)classUSACurrencyFormatter:defformat_currency(self,base,cents):base,cents=(str(x)forxin(base,cents))如果len(cents)==0:cents='00'eliflen(cents)==1:cents='0'+美分数字=[]fori,cinenumerate(reversed(base)):ifiandnoti%3:digits.append(',')digits.append(c)base=''.join(reversed(digits))return"{0}{1}".format(base,cents)classUSAFormatterFactory:defcreate_date_formatter(self):返回USADateFormatter()defcreate_currency_formatter(self):returnUSACurrencyFormatter()classFranceFormatterFactory:defcreate_date_formatter(self):返回FranceDateFormatter()defcreate_currency_formatter(self):返回FranceFormatterFactory()country_code="US"factory_map={"US":USAFormatterFactory,"FR":FranceFormatterFactory}formatter_factory=factory_map.get(country_code)