Python基础 - 工厂与建造者模式

简介

工厂模式与建造者模式都属于创建型模式。

在工厂模式中,客户端在不知道对象来源(即不知道该对象是用哪个类产生的)的情况下,要求创建一个对象。

工厂模式背后的思想是简化对象的创建过程。

工厂模式通常有两种形式:

  • 工厂方法,它是一个方法(或以地道的 Python 术语来说,是一个函数),针对不同的输入参数返回不同的对象。
  • 抽象工厂,它是一组用于创建一系列相关对象的工厂方法。

当需要构建更为复杂的对象时,可以使用建造者模式。

建造者与工程模式的区别:

工厂模式在单个步骤中创建对象,而建造者模式在多个步骤中创建对象,而且几乎总是使用指挥者。

建造者模式通常包括两个部分:

  • 建造者(builder):负责创建复杂对象的各个部分的组件
  • 指挥者(director):使用建造者实例控制构建过程的组件

工厂方法

工厂方法基于单一的函数来处理对象创建任务。执行工厂方法、传入一个参数以提供体现意图的信息,就可以创建想要的对象。

例如:createProduct,只需要提供产品名称就可以返回对应的 Product

  • createProduct( “Product1” )
  • createProduct( “衬衣” )

例如:Django 框架使用工厂方法来创建表单字段

  • forms.CharField(max_length=100)
  • forms.DateField(required=False)

1、什么时候使用工厂方法模式

如果你发现,创建对象的代码分布在许多不同的地方,而不是在单一的函数/方法中,导致 难以跟踪应用中创建的对象,这时就应该考虑使用工厂方法模式了。

工厂方法将对象创建过程集 中化,使得追踪对象变得更容易。

创建多个工厂方法完全没有问题,实践中也通常这么做。

2、工厂方法模式的优点

将对象的创建与使用解耦,修改工程方法十分容易,而且不需要同时修改使用这个工程方法的代码。

工厂方法仅在绝对必要时才创建新的对象,可以提升性能与内存使用率。

3、工厂方法案例1:HTML 按钮工厂

HTML 按钮有几种类型:Button, Input, Image

开发一个工厂方法,通过传入的参数返回不同的按钮的 html 代码

# 工厂方法案例1:HTML 按钮工厂
​
class Button(object):
    html = "<button></button>"
    def get_html(self):
        return self.html
​
class Image(Button):
    html = "<img></img>"
​
class Input(Button):
    html = "<input></input>"
​
def create_button(name):
    c_name = name.capitalize()
    if c_name in ['Button', 'Image', 'Input' ]:
        return globals()[c_name]()
​
print(create_button('image').get_html())
<img></img>

4、工厂方法案例2:将create_button 封装到一个类中

多个工厂方法可以再使用一个类进行封装

# 工厂方法案例2:将create_button 封装到一个类中
# 可以将其他 create 方法都放在 HTMLFactory 中
​
class  HTMLFactory:
    button_types = ['Button', 'Image', 'Input' ]
    def create_button(self, name):
        c_name = name.capitalize()
        if c_name in self.button_types:
            return globals()[c_name]()
​
print(HTMLFactory().create_button('button').get_html())
<button></button>

抽象工厂

抽象工厂设计模式是一种一般化的工厂方法。

一个抽象工厂是一些工厂方法的集合,其中每一个工厂方法负责生成一种不同的对象。

1、什么时候使用 工厂方法、抽象工厂

通常从 简单的工厂方法开始。

如果发现应用程序需要许多工厂方法,且将这些方法组合起来创建一系列 对象是有意义的,那么就使用抽象工厂。

2、抽象工厂案例1:玩具工厂

定义一个抽象工厂,内有多个工厂方法。

定义两个玩具工厂,分别生产汽车玩具,毛绒玩具。

# 抽象工厂案例1:玩具工厂
from abc import ABC, abstractmethod
​
​
class AbstractToy(ABC):
    @abstractmethod
    def name(self) ->str:
        pass
​
    @abstractmethod
    def price(self) -> int:
        pass
​
class AbstractFactory(ABC):
    @abstractmethod
    def create_toy(self, name) -> AbstractToy:
        pass
​
class CarToyFactory(AbstractFactory):
    types = ['BMW', 'Porsche', 'Buick']
    def create_toy(self, name):
        # 这里省略部分代码,具体实现参考工厂方法
        return "Car Toy:" + name
​
class StuffedToyFactory(AbstractFactory):
    types = ['Bear', 'Cat', 'Dog']
    def create_toy(self, name):
        return "Stuffed Toy:" + name
​
factory = CarToyFactory()
print( factory.create_toy('BMW'))
​

Car Toy:BMW

建造者模式

在不太适合使用工厂模式(工厂方法或抽象工厂)的情况下,我们使用建造者模式创建对象。

想要创建一个复杂的对象(一个由许多部分组成的对象,并且可能需要遵循特定的顺序 在不同的步骤中创建)。

需要对象的不同表现形式,并希望保持对象的构造与表示解耦。

希望在某个时间点创建一个对象,但在稍后的时间点访问它。

### 流畅建造者示例
class Pizza:
    def __init__(self, builder):
        self.garlic = builder.garlic
        self.extra_cheese = builder.extra_cheese
    
    def __str__(self): 
        garlic = 'yes' if self.garlic else 'no'
        cheese = 'yes' if self.extra_cheese else 'no'
        info = (f'Garlic: {garlic}', f'Extra cheese: {cheese}')
        return '\n'.join(info)
    
    # 建造者模式
    class PizzaBuilder:
        def __init__(self):
            self.extra_cheese = False
            self.garlic = False
        def add_garlic(self):
            self.garlic = True
            return self
        def add_extra_cheese(self):
            self.extra_cheese = True
            return self
        def build(self):
            return Pizza(self)
​
if __name__ == '__main__':
    pizza = Pizza.PizzaBuilder().add_garlic().add_extra_cheese().build()
    print(pizza)
		```
Garlic: yes
Extra cheese: yes

总结

工厂模式有两种形式:工厂方法与抽象工厂,优先使用工厂方法实现

工厂模式的优点:

将对象的创建与使用解耦,修改工程方法十分容易,而且不需要同时修改使用这个工程方法的代码;

工厂方法仅在绝对必要时才创建新的对象,可以提升性能与内存使用率。

​文源网络,仅供学习之用,如有侵权,联系删除。

我将优质的技术文章和经验总结都汇集在了我的公众号【Python圈子】里,为方便大家学习,还整理了一套学习资料,免费提供给热爱Python的同学! 更有学习交流群,多交流问题才能更快进步~

在这里插入图片描述

发布了38 篇原创文章 · 获赞 1 · 访问量 2173

猜你喜欢

转载自blog.csdn.net/wulishinian/article/details/105090290