前言
前两篇文章介绍了单例模式和工厂模式,这两种设计模式实际上都属于软件工程中的创建型模式(Creational Pattern)。维基百科有对这类模式的定义:
在软件工程中,创建型模式 是处理对象 "对象 (计算机科学)")创建的设计模式 "设计模式 (计算机)"),试图根据实际情况使用合适的方式创建对象。基本的对象创建方式可能会导致设计上的问题,或增加设计的复杂度。创建型模式通过以某种方式控制对象的创建来解决问题。
创建型模式由两个主导思想构成。一是将系统使用的具体类封装起来,二是隐藏这些具体类的实例创建和结合的方式。
实际上创建型模式的最大作用就是把对象的创建过程和使用过程进行了解耦,对使用者只提供接口而隐藏了具体的实现细节,让软件结构更清晰,更符合单一职责的原则。接下来本文将继续介绍创建型模式中的另两种模式——建造者模式和原型模式,文中的代码已托管在Github上。
建造者模式
建造者模式(Builder Pattern)与工厂模式类似,也是把产品的实例化过程交给专门的类来实现,不同的是建造者模式更多的是针对现实中一些构成较复杂,有多个组成部分的对象。比如像汽车就由车身、发动机、车轮、方向盘等很多部件组成,而且整个组装的过程可能还要安装一定的顺序进行。
class Car(object):
"""产品
"""
def __init__(self, name):
self.name = name
self.body = None
self.engine = None
self.tire = None
def __str__(self):
info = ("Name: {}".format(self.name),
"Body: {}".format(self.body),
"Engine: {}".format(self.engine),
"Tire: {}".format(self.tire))
return '\n'.join(info)
但是在现实使用时,用户可能并不关心汽车的这些细节和如何将这些部件组装成汽车的,而只是想通过特定的接口和参数获得汽车这个对象。这时就需要将这个复杂的过程抽象到到一个被称作建造者的对象里,建造者来负责构造这些复杂的组成:
class CarBuilder(object):
"""建造者
"""
def __init__(self):
self.car = Car("Mercedes")
def add_body(self, body):
self.car.body = body
def add_engine(self, engine):
"""AMG 5.5L V8 biturbo"""
self.car.engine = engine
def add_tire(self, tire):
self.car.tire = tire
def assemble_car(self):
return self.car
最后建造者模式中还会引入了一个指挥者类的角色,该类的作用主要是负责精确地控制产品的整个生成过程,根据用户的不同需求返回不同的完整产品对象。
class Engineer(object):
"""指挥者
"""
def __init__(self):
self.builder = None
def construct_car(self, body, engine, tire):
self.builder = CarBuilder()
self.builder.add_body(body)
self.builder.add_engine(engine)
self.builder.add_tire(tire)
return self.builder.assemble_car()
只要把需求告诉指挥者,用户就可以获得一个产品的实例,如下所示:
engineer = Engineer()
car = engineer.construct_car(
body="G63",
engine="AMG 5.5L V8 biturbo",
tire="Michelin 18inch")
print(car)
# Output
>Name: Mercedes
>Body: G63
>Engine: AMG 5.5L V8 biturbo
>Tire: Michelin 18inch
原型模式
原型模式(Prototype design pattern)的动机是为了让用户可以通过复制对象获得一个对象的副本。此模式的出现是因为在C++和Java里需要用此模式来更方便的拷贝对象,但在Python中要实现对一个对象的拷贝有更简单办法,我们就在这里简单的举个例子:
#coding=utf-8
class Foo(object):
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return "id: {}, x: {}, y: {}".format(id(self), self.x, self.y)
if __name__ == '__main__':
foo = Foo(1, 2)
# 利用deepcopy获得新对象
import copy
foo1 = copy.deepcopy(foo)
foo1.x = 3
foo1.y = 4
print(foo, foo1)
# 利用__class__方法获得新
foo2 = foo1.__class__(5, 6)
print(foo, foo2)
# Output
>id: 4312696592, x: 1, y: 2 id: 4312696928, x: 3, y: 4
>id: 4312696592, x: 1, y: 2 id: 4312697096, x: 5, y: 6
上面我们用两种原型方式实现了对Foo对象的拷贝,第一种是利用Python语言内置的deepcopy,第二种则用了更优雅的__class__方法。
结论
本文介绍的两种模式在实际使用中并不常见,建造者模式应用在构造一些复杂的对象时,比如需要构建一个HTML对象,窗口对象或者游戏中的建模等等,而原型模式则主要应用于一些需要备份状态的对象或新建对象开销过大的时候。
参考