抽象工厂(Abstract Factory)模式又称为Kit模式,属于对象创建型模式,它拥有比简单工厂模式和工厂方法模式更高的抽象性,是所有工厂模式中最为抽象和最具一般性的形态。抽象工厂模式是一种重要的架构型组件(Architectural Component),它负责提供统一的接口,用来生成一簇"相互关联"或者"相互依赖"的多态对象(Polymorphic Object)。
考虑一个具有多种风格(Theme)的GUI工具包,它能够同时支持KDE和GNOME等类型的桌面环境,不同的桌面风格负责为诸如按钮、文本框和滚动条这样的窗口控件(Widget)定义不同的外观和行为。很显然,应用程序不应该针对某种特定的桌面风格硬编码它的窗口控件,否则之后如果需要使用另外一种桌面风格就必须对源代码进行修改,或者换句话说,在应用程序中实例化特定桌面风格的窗口控件将使得今后很难再对应用程序的桌面风格进行更改。解决的办法是首先定义一个抽象的WidgetFactory类,它负责声明用于创建每一类窗口控件的公共接口,然后再为每一类窗口控件定义一个共同的抽象父类,并且使用与之对应的具体子类来实现特定风格的窗口控件。对于每一个抽象的窗口控件类,WidgetFactory都提供一个返回相应对象的方法,这样应用程序就可以通过调用这些方法来获得窗口控件的实例,而不用关心当前正在使用的是哪些具体类,从而也就可以不再依赖于某种具体的桌面风格了,整个GUI工具包的系统结构如图1所示。
每一种桌面风格都对应于WidgetFactory的一个具体子类,它们负责实现在WidgetFactory中定义的用来创建相应窗口控件的方法。例如,调用KDEWidgetFactory中的createButton()方法可以创建一个KDE桌面环境下的按钮,而调用GNOMEWidgetFactory中的createButton()方法则可以创建一个GNOME桌面环境下的按钮。此处的WidgetFactory就是一个抽象工厂,它使得应用程序只需通过在WidgetFactory中定义的接口就可以得到相应的窗口控件,而不用关心整个GUI软件包中究竟是哪些类实现了特定风格的窗口控件。运用抽象工厂模式的好处是客户端可以完全独立于产品的创建过程,只要与抽象工厂类中定义的公共接口进行交互就可以了,而无需对具体的产品类进行实例化操作。
抽象工厂模式与工厂方法模式最大的区别在于:工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则针对的是多个产品等级结构。正因如此,在抽象工厂模式中经常会用到产品族(Product Family)这一概念,它指的是位于不同的产品等级结构中,并且功能相互关联的产品系列。图2中箭头所指的就是三个功能相互关联的产品,它们位于三个不同的产品等级结构中的相同位置上,共同组成了一个产品族。
不难看出,如果使用抽象工厂模式,那么仅需要一个工厂等级结构就可以创建出分属于不同产品等级结构的产品族中的所有对象,因此抽象工厂模式同工厂方法模式相比效率更高。抽象工厂这一模式适合在如下场合中运用:
当软件系统要求独立于产品的创建、组合和表示的时候,其实这对任何形态的工厂模式来讲这都是很重要的。
当软件系统要由多个产品族中的一个来进行配置的时候,此时系统中会存在多于一个的产品族,但同一时刻只会消费其中某一族的产品,这是抽象工厂模式的原始用意。
当一簇相关产品被设计成应该被组合使用的时候,即同属于某个产品族的多个产品是需要在一起配套使用的,这一约束必须在系统设计时体现出来。
当需要提供一个产品库,并且只想暴露接口而不是实现的时候,这样所有的产品都能够以同样的接口出现,从而使得客户端可以不依赖于具体的实现。
二、模式引入
抽象工厂模式的一个主要功能是它能够隔离要生成的具体产品类,由于这些类的实际类名都被隐藏在工厂里面,因此客户端根本不需要关心如何对它们进行实例化的细节。每一种设计模式都是针对特定问题的解决方案,而抽象工厂模式面临的问题则是当涉及到有多个产品等级结构时,如何更好地进行软件体系结构的设计。下面从一个具体的问题出发,将抽象工厂模式引入到软件系统的设计中来。
假设我们打算开发一个类似于Doom或者Quake那样的格斗类游戏,为了适应不同等级玩家的需要,游戏特地安排了两个难度级别:初等级别和高难级别。在初等级别中,敌方士兵反映迟钝,怪兽步履缓慢,即便是初学者也能够很轻松地取胜;但在高难级别中,敌方士兵反映敏捷,怪兽狰狞狡诈,就算是高级玩家也难逃被击毙的厄运。
在具体实现时可以先设计两个抽象产品类Soldier和Monster,用来代表士兵和怪兽,然后再分别从它们派生出SillySoldier和SillyMonster两个具体产品类用于初等级别,以及WiseSoldier和WiseMonster两个具体产品类用于高难级别。设计时一个值得注意的问题是,游戏在运行的过程中SillySoldier和WiseMonster是绝对不能同时出现的,因为玩家要么就与SillySoldier和SillyMonster进行实战演练,要么就与WiseSoldier和WiseMonster展开艰苦的战斗。不难看出,游戏在设计时依据难度级别形成了两个产品族,玩家在游戏期间肯定会使用这两个产品族中的某一族对象,但绝对不会同时使用它们。
为了保证这种一致性,程序员在编码时必须非常小心,否则稍有疏忽,那些正在痛击SillySoldier的游戏菜鸟们一转身撞上一个WiseMonster,肯定会败得一塌糊涂。抽象工厂模式可以很好地解决这一问题,在具体实现时可以先将游戏中所有Soldier和Monster对象的生成函数集中到一个抽象工厂AbstractEnemyFactory中,然后再根据不同的难度级别依次构造SillyEnemyFactory和WiseEnemyFactory两个具体工厂,并由它们负责按照当前游戏策略的要求去生成具体的士兵和怪兽。这样一来,整个游戏的体系结构就将如图3所示。
AbstractEnemyFactory 是一个抽象工厂,它负责声明被所有具体工厂所共有的构造性方法,其完整的代码如清单1所示。在AbstractEnemyFactory中定义的createSoldier()和createMonster()是两个抽象方法,它们必须在所有的具体工厂中给出相应的实现,这样客户端才有可能通过调用具体工厂中的这两个方法,来获得所需要的某种Soldier或者Monster对象。
代码清单1:abstractenemyfactory.py
class AbstractEnemyFactory:
""" 负责创建Soldier和Monster的抽象工厂 """
# 创建Soldier的抽象方法
def createSoldier(self):
pass
# 创建Monster的抽象方法
def createMonster(self):
pass
SillyEnemyFactory 是 AbstractEnemyFactory 的一个具体实现,它负责实例化 SillySoldier 和 SillyMonster 对象,其完整的代码如清单2所示。
代码清单2:sillyenemyfactory.py
from sillysoldier import *
from sillymonster import *
from abstractenemyfactory import *
class SillyEnemyFactory(AbstractEnemyFactory):
""" 负责创建SillySoldier和SillyMonster的具体工厂 """
# 创建SillySoldier的具体方法
def createSoldier(self):
soldier = SillySoldier()
return soldier
# 创建SillyMonster的具体方法
def createMonster(self):
monster = SillyMonster()
return monster
WiseEnemyFactory 是 AbstractEnemyFactory 的另一个具体实现,它负责实例化 WiseSoldier 和 WiseMonster 对象,其完整的代码如清单3所示。
代码清单3:wiseenemyfactory.py
from wisesoldier import *
from wisemonster import *
from abstractenemyfactory import *
class WiseEnemyFactory(AbstractEnemyFactory):
""" 负责创建WiseSoldier和WiseMonster的具体工厂 """
# 创建WiseSoldier的具体方法
def createSoldier(self):
soldier = WiseSoldier()
return soldier
# 创建WiseMonster的具体方法
def createMonster(self):
monster = WiseMonster()
return monster
AbstractEnemyFactory 、 SillyEnemyFactory 和 WiseEnemyFactory 共同组成了抽象工厂模式中的工厂等级结构,其作用是为了更好地创建相应的 Soldier 和 Monster 产品对象。 Soldier 是游戏中所有士兵对象的抽象接口,其完整的代码如清单4所示。
代码清单4:soldier.py
class Soldier:
""" 所有士兵对象的抽象接口 """
# 获取速度的抽象方法
def getSpeed(self):
pass
# 获取武器的抽象方法
def getWeapon(self):
pass
SillySoldier 是 Soldier 的一个具体实现,它用来代表初等游戏级别中的士兵对象,其完整的代码如清5所示。
代码清单5:sillysoldier.py
from soldier import *
class SillySoldier(Soldier):
""" 初等级别中士兵对象的具体实现 """
# 构造函数
def __init__(self):
print "A SillySoldier is created."
self.speed = 10
self.weapon = "saber"
延伸阅读
文章来源于领测软件测试网 https://www.ltesting.net/