python算法基础设计模式,精通python设计模式第2版

  python算法基础设计模式,精通python设计模式第2版

  在这一系列文章中,我们希望用通俗易懂的语言解释软件项目中最常见的设计模式,并在Python上实现它们。每个设计模式都围绕以下三个问题。

  为什么?也就是说为什么要用这种设计模式?使用这种模式之前有什么问题?

  这个设计模式是用Python语言实现的,以解决为什么提到它。

  怎么用?我们也基本了解了为什么以及在什么情况下使用这种模式,但这里我们将细分使用场景,说明这种模式的局限性和优缺点。

  这次的主角是简单工厂,工厂方法,抽象工厂模型。这些模型密切相关,具有一定的相似性。我们来总结一下。

  静态工厂方法

  为什么?

  工厂模式中最常见的例子是比萨饼店。我们用这个典型的例子。假设我们开了一家披萨店。此外,我们还准备了几种披萨供顾客选择。如下图。

  classcheesepizza(对象) :

  classvegetablepizza(对象) :

  #你可以继续定义不同类型的披萨。

  然后我们就可以定义我们的披萨店生产披萨了。

  Classpizzastore(对象):

  deformer _ pizza(self,pizza_type):

  -

  if pizza_type==cheese :

  self.pizza=芝士披萨(

  elif pizza _ type==蔬菜 :

  self.pizza=蔬菜披萨(

  否则:

  self.pizza=SeafoodPizza(

  -

  self .披萨. prepare(

  self.pizza.bake

  self .披萨. cut(

  self .披萨. box(

  回归自我.披萨

  这里的问题是,我们的产品,也就是不同类型的披萨,可能会发生变化。比如,随着时间的推移,会增加几种类型的披萨,也会删除一些冷门的披萨类型。此时,您需要修改order_pizza()水平线周围的代码。我们的设计原则之一就是将“变化”分离打包。这就是工厂方法模式的初衷。

  这是什么?

  简单的工厂模型就是把创建不同类型实例的代码分离封装成一个工厂类(其实我觉得用函数更直接)。这个工厂类别专门为客户生产不同的产品(这里是披萨产品)。这是订购比萨饼。顾客不需要知道如何制作这些披萨。顾客只需要告诉工厂他们需要奶酪披萨还是其他类型的披萨。然后,工厂会退回适合顾客的披萨。代码如下。

  Classsimplepizzafactory(对象):

  @静态方法

  defcreate_pizza(pizza_type):

  #在实际的APP应用中,还可以使用配置文件和反射机制来实现create_pizza。这样,您只需要在添加新的披萨类型时更改配置文件。

  pizzas=Dict(cheese=cheesepizza,vegetable=VegetablePizza,seafood=SeafoodPizza))。

  退货披萨[pizza_type](

  原始PizzaStore修改如下:

  Classpizzastore(对象):

  deformer _ pizza(self,pizza_type):

  -

  self . pizza=simple pizza factory . create _ pizza(pizza _ type))。

  -

  self .披萨. prepare(

  self.pizza.bake

  self .披萨. cut(

  self .披萨. box(

  回归自我.披萨

  如何使用

  看了上面的代码,很多同学可能会怀疑,只是代码被转移到别的地方了,好像很少用到彩蛋。简单的工厂模型不仅可以封装创建实例的代码,使代码更容易理解,还具有在其他客户需要创建相同实例时直接调用工厂的create_pizza()的优点。例如,我们有一门外卖课:

  classpizzatakeout(对象) :

  /p def order_pizza(self,pizza_type):

  # -

  self . pizza=simple pizza factory . create _ pizza(pizza _ type)

  # -

  .

  在这种情况下,如果添加或删除一个产品(Pizza类),我们只需要简单地更新一处代码(即在简单工厂中创建实例的代码)。

  另一个好处是,一个大系统往往是在不同的层次和模块上开发的。当开发客户端(这里是PizzaStore)的程序员和开发底层产品(这里是各种披萨)的程序员不是同一个人的时候会非常有用,因为开发客户端的程序员在通过工厂创建对象的时候不需要关注如何创建不同的产品。他只需要把客户的要求(pizza_type)传递给工厂就可以了。

  工厂方法和抽象工厂

  为什么?

  在一个简单的工厂中,我们通常只创建一个产品,但往往很难处理一组产品的创建。想想吧。如果我们要创建一组汽车零部件产品,如果我们使用工厂方法模式,代码可能如下:

  SimpleCarPartsFactory类(对象):

  def __init__(self,car_type):

  self.car_type=汽车类型

  定义创建_引擎(自身):

  engines=dict(small=小型引擎,medium=中型引擎,big=大型引擎)

  返回引擎[self.car_type]()

  定义创建_轮子(自身):

  wheels=dict(small=small wheels,medium=MediumWheeles,big=BigWheeles)

  返回车轮[self.car_type]()

  .

  虽然这段代码可以勉强使用,但想象一下,如果我添加另一辆superbig类型的汽车,我需要修改所有的创建方法吗?如果修改了一个组件类或者删除了某一类组件,需要修改这个类吗?如果这些都是你自己改变的呢?

  这就是为什么我们需要工厂方法和抽象工厂。

  这是什么?

  首先,什么是工厂法?工厂方法是将客户端程序抽象成一个父类,然后在其子类中实现创建产品的方法。这个方法是工厂方法。

  Class PizzaStore(object): #客户端程序抽象父类。

  定义订单_披萨(自身,披萨_类型):

  # -

  self . pizza=self . create _ pizza(pizza _ type)

  # -

  self.pizza.prepare()

  self.pizza .烘焙()

  self.pizza.cut()

  self.pizza.box()

  回归自我.披萨

  Def _ pizza (self,pizza _ type): #抽象工厂方法

  及格

  class Beijing pizza store(pizza store):#客户端程序的子类

  Def _ pizza (self,pizza _ type): #特定工厂方法

  披萨=Dict(奶酪=独家香菇,蔬菜=北京蔬菜披萨,海鲜=北京海鲜披萨)#不同的子类可能使用不同的产品。

  返回比萨饼[比萨饼类型]()

  上海披萨店(PizzaStore):

  def create_pizza(self,pizza_type):

  披萨=dict(奶酪=上海奶酪披萨,蔬菜=上海蔬菜披萨,海鲜=上海海鲜披萨)

  返回比萨饼[比萨饼类型]()

  在这里,如果我们使用工厂方法模式来实现它,我们必须向create方法多传递一个region参数(例如, beijing ),然后在方法中进行两个条件判断(region和pizza type),这有点不优雅。

  实际上,软件设计的原则也体现在这里。改变的地方被抽象/继承封装。因为会有‘不同’种类的产品,所以会有‘不同’的create_pizza。然后我们可以抽象PizzaStore并通过继承实现“不同的”create_pizza factory方法。

  不管怎样,现在我们知道了什么是工厂方法模式,让我们来看看另一种设计模式——抽象工厂,它实际上使用了工厂方法模式。而抽象工厂才是我们前面提到的一组产品问题的真正解决方案。

  利用抽象工厂实现汽车零部件的实例化生产:

  ClassAbstractPartsFactory(object):这个抽象类甚至可以在# Python中省略,但是为了清楚起见,创建了这个父类。

  定义创建_引擎(自身):

  通行证

  定义创建_轮子(自身):

  及格

  .

  class smallcarpartsfactory(abstractcarpartsfactory):#不同类型的汽车工厂维护自己的实例创建。

  Def _ engine (self): #具体工厂方法

  返回SmallEngine()

  定义创建_轮子(自身):

  返回小轮子()

  .

  类MediumCarPartsFactory(AbstractCarPartsFactory):

  定义创建_引擎(自身):

  返回SmallEngine()

  定义创建_轮子(自身):

  返回小轮子()

  .

  .

  使用时,如下所示:

  类别CarFactory(对象):

  def create_car(自身,汽车类型):

  car _ factorys=dict(

  small=SmallCarPartsFactory, medium=MediumCarPartsFactory,

  BigCarPartsFactory)

  self . car parts _ factory=car _ factory ys[car _ type]()

  self.prepare_parts():

  self . engine=self . cart parts _ factory . create _ engine()

  self . wheels=self . cart parts _ factory . create _ wheels()

  .

  self.compose_parts()

  自我绘画()

  .

  从上面的例子可以看出,我们首先把生产一组产品的工厂抽象成一个工厂类(即AbstractFactory),这就是抽象工厂这个名字的由来。然后,我们通过不同的子类工厂实例化具体的产品,在子类中实例化产品。听起来耳熟吗?是的,这里用的是工厂方法模式,所以抽象工厂用的是工厂方法模式,但它们是不同的模式。请注意这里的区别。

  这时,如果我们想增加一个新的汽车类型,我们只需要增加一个子类。容易追上吗?

  如何使用

  总结一下,所谓工厂就是用来生产产品的(也就是创建实例)。当我们只有一种产品时,我们不需要工厂。只有当有多种类型的产品时,我们才需要一个工厂来帮助我们选择一个特定的类来实例化。

  一般简单的使用场景,工厂方法模式足以应付。当我们需要同时初始化一组产品,并且每个产品都有多个类型时,就需要抽象工厂来处理(个人认为单独使用工厂方法模式效果不明显,但是可以在抽象工厂中最大化其价值)。

  总之,当有很多实用的书包需要实例化的时候,考虑工厂模式!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: