一、创建型模式
创建型模式(Creational Pattern)对类的实例化过程进行了抽象,能够使软件模块做到与对象创建和组织的无关性。为了使体系结构更加清晰,一些软件在设计上要求当创建类的具体实例时,能够根据具体的语境来动态地决定怎样创建对象,创建哪些对象,以及怎样组织和表示这些对象,而创建型模式所要描述的就是该如何来解决这些问题。
按照生成目标的不同,创建型模式可以分为类的创建型模式和对象的创建型模式两种:
类的创建型模式
类的创建型模式通过使用继承关系,将类的创建交由具体的子类来完成,这样就向外界隐藏了如何得到具体类的实现细节,以及这些类的实例是如何被创建和组织在一起的。
对象的创建型模式
对象的创建型模式通过把对象的创建委托给另一个对象来完成,可以根据语境动态地决定生成哪些具体类的实例,同时还可以向外界隐藏这些实例是如何被创建以及如何被组织在一起的细节。
所有的创建型模式都有两个永恒的主旋律:第一,它们都将系统使用哪些具体类的信息封装起来;第二,它们隐藏了这些类的实例是如何被创建和组织的。外界对于这些对象只知道它们共同的接口,而不清楚其具体的实现细节。正因如此,创建型模式在创建什么(what),由谁(who)来创建,以及何时(when)创建这些方面,都为软件设计者提供了尽可能大的灵活性。
具体到Python来说,假设有这样一个类:
class Person:
def __init__(self, name):
self.name = name
要创建该类的一个实例,则应该执行下面的语句:
p = Person("Gary")
但如果创建对象时完成的工作非常复杂,需要一段很长的代码,你就不能简单地将其全部写入__init__方法中,因为这会违背面向对象思想的两个基本原则:封装(encapsulation)和委派(delegation)。假如执意要做样做,结果只会使你的代码变成一段行为固定的硬编码(hard coding),而整个软件的结构都极有可能变得非常糟糕,因为其它某个模块也许就正依赖于你所创建的这个实例,这样就在无形之间增加了模块之间的耦合度。
将Python对象的创建过程封装到某个类中来单独完成,可以使你的程序变得更加灵活和通用。实践证明,使用下面的六种创建型模式可以更好地改善对象的创建过程:
Simple Factory模式
专门定义一个类来负责创建其它类的实例,被创建的实例通常都具有共同的父类。
Factory Method模式
将对象的创建交由父类中定义的一个标准方法来完成,而不是其构造函数,究竟应该创建何种对象由具体的子类负责决定。
Abstract Factory模式
提供一个共同的接口来创建相互关联的多个对象。
Singleton模式
保证系统只会产生该类的一个实例,同时还负责向外界提供访问该实例的标准方法。
Builder模式
将复杂对象的创建同它们的具体表现形式(representation)区别开来,这样可以根据需要得到具有不同表现形式的对象。
Prototype模式
利用一个能对自身进行复制的类,使得对象的动态创建变得更加容易。
二、模式引入
简单工厂(Simple Factory)模式又称为静态工厂方法(Static Factory Method)模式,属于类的创建型模式。这种模式根据外界给定的信息,由"工厂"对象"制造"出某些可能"产品"类中的一个实例,工厂对象能够处理的所有类通常都继承于同一个父类,并且对外界提供基本相同的接口,只不过在具体实现时会有所差别罢了。
假设我们要开发一个绘图程序,用来绘制简单的几何图形,这个软件应该能够处理下面的几种几何对象:
圆形(Circle)
矩形(Rectangle)
菱形(Diamond)
除了各自特有的属性和方法之外,所有的几何图形几乎都可以抽象出绘制(draw)和擦除(erase)两个公共方法,因而可以为它们定义一个共同的接口Shape。虽然Python语言本身并不支持接口,但为了更好地阐明设计模式的思想,有时我们还是会借用一下UML中的接口这一概念。这样一来,各个类之间的关系就将如图1所示:
图1
Shape接口定义了所有几何图形都必须实现的公共方法: draw()和erase(),实现该接口的Python代码如下所示,Python中没有接口的概念,因此在具体实现时可以使用类来替代。
代码清单1:shape.py
class Shape:
# 绘制图形
def draw(self):
pass
# 擦除图形
def erase(self):
pass
Circle类是Shape的一种具体形式,它实现了Shape接口定义的所有方法,此外还添加了一个属性__radius,用来表示圆的半径。以下是实现Circle类的代码:
代码清单2:circle.py
class Circle (Shape):
def __init__(self, radius = 0):
self.__radius = radius
# 绘制圆形
def draw(self):
print "Draw Circle"
# 擦除圆形
def erase(self):
print "Erase Circle"
# 半径的取值方法
def getRadius(self):
return self.__radius
# 半径的赋值方法
def setRadius(self, radius):
self.__radius = radius
Rectangle类也是Shape的一种具体形式,它实现了Shape接口定义的所有方法,并添加了__width和__height两个属性,分别表示矩形的宽度和高度。以下是实现Rectangle类的代码:
代码清单3:rectangle.py
class Rectangle (Shape):
def __init__(self, width = 0, height = 0):
self.__width = width
self.__height = height
# 绘制矩形
def draw(self):
print "Draw Rectangle"
# 擦除矩形
def erase(self):
print "Erase Rectangle"
# 宽度的取值方法
def getWidth(self):
return self.__width
# 宽度的赋值方法
def setWidth(self, width):
self.__width = width
# 高度的取值方法
def getHeight(self):
return self.__height
# 高度的赋值方法
def setHeight(self, height):
self.__height = height
同样,Diamond类也是Shape的一种具体形式,它实现了Shape接口中定义的所有方法,并且添加了__width和__height两个属性,分别表示菱形的宽度和高度。以下是实现Diamond类的代码:
代码清单4:diamond.py
class Diamond (Shape):
def __init__(self, width = 0, height = 0):
self.__width = width
self.__height = height
# 绘制菱形
def draw(self):
print "Draw Diamond"
# 擦除菱形
def erase(self):
print "Erase Diamond"
# 宽度的取值方法
def getWidth(self):
return self.__width
# 宽度的赋值方法
def setWidth(self, width):
self.__width = width
# 高度的取值方法
def getHeight(self):
return self.__height
# 高度的赋值方法
def setHeight(self, height):
self.__height = height
所有几何图形类都定义好后,下面要做的就是提供一个"工厂"类ShapeFactory,来创建各种几何图形的具体实例。ShapeFactory类的作用就是根据外界的要求,创建出不同的几何图形对象,如圆形(Circle)、矩形(Rectangle)或菱形(Diamond),这样整个软件的体系结构就将如图2所示。
图2
ShapeFactory类用于创建各种几何图形的实例,其实现代码如下所示:
代码清单5:shapefactory.py
class ShapeFactory:
def factory(self, which):
if which == "Circle":
return Circle()
elif which == "Rectangle":
return Rectangle()
elif which == "Diamond":
return Diamond()
else:
return None
在ShapeFactory类中只定义了一个方法factory(),外界通过调用该方法,来创建其所需的几何图形对象,但如果所请求的类是系统所不支持的,则将返回None。在引入了工厂类之后,其它模块如果想生成几何图形类的实例,只需调用ShapeFactory类的factory()方法就可以了:
fac = ShapeFactory()
shape = fac.factory("Diamond")
if shape != None:
shape.draw()
就样就成功地将类是如何创建的这一实现细节向外界隐藏起来了,这就是简单工厂模式所采取的基本策略。
三、一般结构
简单工厂模式属于类的创建型模式,适合用来对大量具有共同接口的类进行实例化,它可以推迟到运行的时候才动态决定要创建哪个类的实例