多平台统一管理软件接口,如何实现多平台统一管理软件接口
373
2022-06-14
工厂模式是一个令初学者非常费解的模式。因为介绍工厂模式的时候会连续介绍1个编程习惯和2个设计模式,分别是「简单工厂」设计习惯、「工厂方法模式」和「抽象工厂模式」,难以一次理清楚几个重要知识点的逻辑。不过据网上各种大佬所说,平时写代码的时候一般都只会使用简单工厂,而工厂方法模式和抽象工厂模式一般只有大项目才会用,很多人甚至一辈子都用不上。比如,PyTorch Geometric开源工具包的大佬作者Matthias Fey最近提出的 GNNAutoScale 的开源代码也只是用简单工厂来写代码。可见工厂方法模式和抽象工厂模式只是大工程中的“屠龙术”,平时写代码估计很难遇上了,学了也难以和实践结合。本文只是对工厂模式粗浅介绍,如有不对的地方请大家指出。
本文分为以下几个部分:
为什么new需要封装?
简单工厂
工厂方法模式
抽象工厂模式
总结
为什么new需要封装?
new是java中的一个语法,作用是声明并初始化一个变量或对象,就想C中的int、float一样。在python中,我们虽然不用new来实现它,但也总是会隐式地声明和初始化变量或对象。大学刚接触编程那会儿,几乎所有C的代码一上来就会“int x = 0;”这样声明初始化变量,根本没听说过变量或对象初始化还要封装的。但是工厂模式就是将这些初始化变量的代码封装成一个工厂,和其他部分「解耦」。
然而实际项目和考试不一样,实际项目是需要合作写代码的,需要接着别人的代码进行开发的。我们要做的常常是「调用别人的代码」,而「不要自己去new别人负责的模块」。因为这时候别人哪怕是把他的模块改个名字,都会导致你的模块出问题,需要迫使你修改自己负责那部分。自己这块代码会被别人负责的模块牵着走。
工厂模式就是将这种关系「解耦」,让自己负责的代码部分「经得起推敲」。什么叫“经得起推敲”?「少修改叫做“经得起推敲”」。很多时候仅仅是需求发生改变就需要修改自己的这部分代码,那自己写的那部分代码就不算是经得起推敲的。
简单工厂
假如我们要实现一个制作PizzaStore的类的orderPizza函数。函数一开始会传入一个str表示顾客要哪种pizza,而你需要负责整个流程,保证pizza按照prepare、bake、cut、box四道工序做出来。以下是代码示例:
class PizzaStore():
def orderPizza(self,name):
if name in ['cheese']:
pizza = CheesePizza()
elif name in ['greek']:
pizza = GreekPizza()
elif name in ['pepperoni']:
pizza = PepperoniPizza()
pizza.prepare()
pizza.bake()
pizza.cut()
pizza.box()
return pizza
注意到在这段代码中,每个pizza类(CheesePizza、GreekPizza、PepperoniPizza)和里面的方法(prepare、bake、cut、box)都不是自己实现的,我们只是想调用别人已经实现好的。
对于方法(prepare、bake、cut、box),我们的调用不会有问题。因为在框架设计时,这些接口就约定好了,不能随意修改。然而对于pizza类(CheesePizza、GreekPizza、PepperoniPizza),「一但有新pizza类型出现或者原本的pizza被删除,那就要修改orderPizza函数」。
熟悉简单工厂的人会写出下面的代码:
def create_pizza(name):
if name in ['cheese']:
pizza = CheesePizza()
elif name in ['greek']:
pizza = GreekPizza()
elif name in ['pepperoni']:
pizza = PepperoniPizza()
return pizza
class PizzaStore():
def orderPizza(self,name):
pizza = create_pizza(name)
pizza.prepare()
pizza.bake()
pizza.cut()
pizza.box()
return pizza
看起来和之前一个没有本质区别,仅仅是「把pizza初始化的过程封装了起来」。其实这是一个很重要的变化,那就是我们可以说PizzaStore函数「经得起推敲」了,因为在一些新的pizza需求来临时,我们「不需要修改PizzaStore函数」,只需要修改create_pizza。而create_pizza可以再交给负责pizza类各种实现的人来负责。
工厂方法模式
相比于简单工厂,工厂方法模式通过「让子类决定该创建的对象」是什么,来达到将对象创建的过程封装的目的。其代码实现如下
class PizzaStore():
def orderPizza(self,name):
pizza = self.create_pizza(name)
pizza.prepare()
pizza.bake()
pizza.cut()
pizza.box()
return pizza
def create_pizza(self,name):
raise NotImplementedError
这次连create_pizza都不写了,而是把它「交给了别人」——继承PizzaStore类的人。这样我们的PizzaStore类就是更加经得起推敲了。
抽象工厂模式
抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。抽象工厂模式和工厂方法模式一样,都让子类决定该创建的对象是什么。不同之处在于,工厂方法模式设计中的子类只能创建一个产品,而「抽象工厂模式中的子类能创建多个同类型产品」。多个同类型产品是通过策略模式提到的「组合」实现的。
实际上,抽象工厂模式在指导如何「设计子类」,也就是PizzaStore的子类,让**每个子类能创建多个产品****。其代码如下
class NYPizzaStore(PizzaStore):
def __init__(self, ingredientFactory):
self.ingredientFactory = ingredientFactory
def create_pizza(self,name):
if name in ['cheese']:
pizza = NYCheesePizza(self.ingredientFactory)
elif name in ['greek']:
pizza = NYGreekPizza(self.ingredientFactory)
elif name in ['pepperoni']:
pizza = NYPepperoniPizza(self.ingredientFactory)
return pizza
注意其中的ingredientFactory也是个工厂。NYPizzaStore将ingredientFactory作为初始化pizza对象时候的输入,这样就能得到基于「多种原材料」生产的pizza了。
总结
工厂模式遵循「开放-封闭原则」,将已经验证无误的代码封装好,与(经常需要修改的)创建的对象的部分「解耦」。三种工厂的区别如下
简单工厂:「唯一工厂类,一个产品抽象类」,工厂类的创建方法依据入参判断并创建具体产品对象。
工厂方法模式:继承得到「多个工厂类,一个产品抽象类」,利用多态创建不同的产品对象,避免了大量的if-else判断。
抽象工厂模式:继承得到「多个工厂类,组合得到多个产品抽象类」,产品子类分组,同一个工厂实现类创建同组中的不同产品,减少了工厂子类的数量。
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~