简介
抽象工厂设计模式属于创建型设计模式的一种,创建型设计模式更关注对象是如何被创建出来的。通常我们会调用对象的构造函数来创建对象实例,比如通过向类名称传递相关参数来创建。但是,有时候我们会需要更加灵活的对象创建方式,这时创建型的设计模式就会大有用处了。今天我们主要关注创建型的设计模式中的抽象工厂设计模式。抽象工厂设计模式主要用于对于某一个系统而言,根据配置文件的不同或者系统平台(windows/mac/linux)的不同有多种不同的实现方式的时候。
比如:在一个GUI系统里,我们可能有一个抽象的窗口小部件工厂,而这个工厂有三个具体实现子类工厂:MacWidgetFactory, xfceWidgetFactory和WindowsWidgetFactory, 所有的这些子类工厂中都提供了创建相同窗口小部件的方法,比如类似于make_button(), make_spinbox()等等,这些方法则根据不同的平台提供了不同的具体实现。这样,我们就可以通过向同一个函数create_dialog()传递不同的工厂实例,从而产生出平台相关的不同的窗口的外观样式,比如:windows样式的、mac样式的。
一个典型的抽象工厂
为了演示抽象工厂设计模式,我们来看一个产生简单图表的程序。在这个程序里我们设计了两个不同的工厂:一个产生纯文本方式的图表,二另外一个输出可缩放的矢量图形式。输出图形如图1所示。
图1 程序输出结果
首先看一下main()函数:
textFilename与svgFilename是两个文件,用来存储diagram的相关信息,我们调用了相同的create_diagram函数,并传递了不同的工厂实例,从而返回了不同的结果。依据不同的配置文件返回了不同的处理结果,这是典型的抽象工厂模式。我们来更进一步查看create_diagram是如何定义的。
这个函数接受一个factory作为它唯一的参数,并根据factory的不同创建不同的图表。这个函数并不知道或者根本不关心它所接收的到底是哪一类工厂,只要它支持图表工厂的接口即可。下面我们来看下这两个不同的工厂是如何定义的。
上述是纯文本格式图表工厂的定义,实际上它也是基类工厂,svgDiagramFactory是派生自这个工厂的。尽管这种设计模式采用了“抽象”这个词语,在实际实现过程中,比较常见的做法是将某个类既作为基类提供相应的接口,同时它本身又是一个具体的子类。本例中的DiagramFactory即是这样使用的。
上面是svg图表工厂的几行代码,与纯文本格式图表工厂的make_diagram()方法唯一的不同在于纯文本格式图表工厂的make_diagram()方法返回了一个Diagram对象。而svgDiagramFactory的make_diagram()方法返回了一个SvgDiagram对象。make_rectange和make_text()方法与之类似。
纯文本格式的图表工厂用一个由一系列单字符列表组成的列表来存储相应的信息,这些单字符从图1中就可以看出来包括了空格、+、-、|、%等等。程序会在初始化的时候,将由width和height参数指定的宽和高覆盖的区域,初始化成一系列空格覆盖的区域。当调用add方法的时候,就会将rectangle及text指定的位置替换成上述的单字符及本身包含的字符内容。
这个是Text类的所有代码,对于纯文本格式的图表工厂最后一个fontsize参数可以忽略。可以看到,Text类中保存了一个rows的列表,该列表的每个元素也是一个列表,其元素为text中的每个字符。
这是Diagram的add方法,它接收一个component(即Text或者Rectangle)为参数,而后遍历component中保存的rows参数,并将diagram中的相应位置替换成相应的字符串。
这个是SvgText的类代码,以及它所以来的两个常量的定义。使用 **locals()这种定义方法,可以简化代码,而无需写成如下的格式SVG_TEXT.format(x=x,y=y,text=text,fontsize=fontsize)。而从Python3.2开始,可以使用SVG_TEXT.format_map(locals())代替,因为str.format_map()帮助我们进行了参量的解压缩。对于SvgDiagram类而言,每个实例里存储着一个字符串列表self.digram,列表里的每个元素都是一段html代码。这样就使得添加新的SvgRectangle和SvgText等类型的组件非常方便。
上述代码虽然以抽象工厂模式的代码实现了相应的功能,但代码不够简洁,不够pythonic,所以第二篇文章,我们希望能够通过相应的改进,能够让代码更加简洁并且pythonic化,敬请期待!
好了,这个是我们面向对象程序设计里的抽象工厂方法的第一篇文章,喜欢的话给个赞吧,谢谢!
原文地址:http://blog.51cto.com/13466841/2127217