您的位置:首页 > 编程语言 > Python开发

[Python编程实战] 第一章 python的创建型设计模式1.1抽象工厂模式

2017-02-09 15:04 190 查看
注:关乎对象的创建方式的设计模式就是“创建型设计模式”(creational design pattern)

1.1 抽象工厂模式

“抽象工厂模式”(Abstract Factory Pattern)用来创建复杂的对象,这种对象由许多小对象组成,而这些小对象都属于某个特定的“系列”(family)。

比如说,在GUI 系统里可以设计“抽象控件工厂”(abstract widget factory),并设计三个“具体子类工厂”(concrete subclass factory):MacWidgetFactory、XfceWidgetFactory、WindowsWidgetFactory,它们都创建同一种对象的方法(例如都提供创建按钮的make_button()方法,都提供创建数值调整框的make_spinbox()方法),而具体创建出来的风格则和操作系统平台相符。我们可以编写create_dialog()函数,令其以“工厂实例”(factory instance)为参数来创建OS X、Xfce及Windows风格的对话框,对话框的具体风格取决于传进来的工厂参数。

1.1.1经典的工厂模式

self.svg = SVG_TEXT.format(**locals())

其中,使用**locals()的好处是比较省事,这样就不用再写成SVG_TEXT.format(x=x, y=y, text=text, fontsize=fontsize)了。且从Python3.2开始,还可以把SVG_TEXT.format(**locals())写成SVG_TEXT.format_map(locals()),因为str.format_map()方法会自动执行“映射解包”(mapping unpacking)操作。

1.1.2 Python风格的工厂模式

之前的写法有几个缺点:

a.两个工厂都没有各自的状态,所以根本不需要创建实例。

b.SvgDiagramFactory与DiagramFactory的代码基本上一模一样,只不过前者的make_diagram方法返回SvgText实例,而后者返回Text实例,其他的方法也如此,这会产生许多无谓的重复的代码。最后,DiagramFactory、Diagram、Rectangle、Text类以及SVG系列中与其对应的那些类都放在了“顶级命名空间”(top-level namespace)里

c.给SVG的组建类起名时,需加前缀,使得代码显得不够整洁。

class DiagramFactory:

@classmethod
def make_diagram(Class, width, height):
return Class.Diagram(width, height)

@classmethod
def make_rectangle(Class, x, y, width, height, fill="white",
stroke="black"):
return Class.Rectangle(x, y, width, height, fill, stroke)

@classmethod
def make_text(Class, x, y, text, fontsize=12):
return Class.Text(x, y, text, fontsize)


以make 开头的方法现在都变成了“类方法”(class method)。也就是说,调用这些方法时,其首个参数是类,而不像普通的方法那样,首个参数是self。例如,当调用DiagramFactory.make_text()方法时,Class参数就是DiagramFactory,此方法会创建DiagramFactory.Text对象并将其返回。

这种方法使得SvgDiagramFactory子类只需继承DiagramFactory,而不用再去实现那几个make方法了。

def main():
if len(sys.argv) > 1 and sys.argv[1] == "-P": # For regression testing
create_diagram(DiagramFactory).save(sys.stdout)
create_diagram(SvgDiagramFactory).save(sys.stdout)
return
textFilename = os.path.join(tempfile.gettempdir(), "diagram.txt")
svgFilename = os.path.join(tempfile.gettempdir(), "diagram.svg")

txtDiagram = create_diagram(DiagramFactory)
txtDiagram.save(textFilename)
print("wrote", textFilename)

svgDiagram = create_diagram(SvgDiagramFactory)
svgDiagram.save(svgFilename)
print("wrote", svgFilename)


经过上述改变,main()函数也可以简化,因为现在不需要再创建工厂类的实例了。

附录:

1 #!/usr/bin/env python3
2 # Copyright 漏 2012-13 Qtrac Ltd. All rights reserved.
3 # This program or module is free software: you can redistribute it
4 # and/or modify it under the terms of the GNU General Public License as
5 # published by the Free Software Foundation, either version 3 of the
6 # License, or (at your option) any later version. It is provided for
7 # educational purposes and is distributed in the hope that it will be
8 # useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 # General Public License for more details.
11
12 import os
13 import sys
14 import tempfile
15
16
17 def main():
18     if len(sys.argv) > 1 and sys.argv[1] == "-P": # For regression testing
19         create_diagram(DiagramFactory).save(sys.stdout)
20         create_diagram(SvgDiagramFactory).save(sys.stdout)
21         return
22     textFilename = os.path.join(tempfile.gettempdir(), "diagram.txt")
23     svgFilename = os.path.join(tempfile.gettempdir(), "diagram.svg")
24
25     txtDiagram = create_diagram(DiagramFactory)
26     txtDiagram.save(textFilename)
27     print("wrote", textFilename)
28
29     svgDiagram = create_diagram(SvgDiagramFactory)
30     svgDiagram.save(svgFilename)
31     print("wrote", svgFilename)
32
33
34 def create_diagram(factory):
35     diagram = factory.make_diagram(30, 7)
36     rectangle = factory.make_rectangle(4, 1, 22, 5, "yellow")
37     text = factory.make_text(7, 3, "Abstract Factory")
38     diagram.add(rectangle)
39     diagram.add(text)
40     return diagram
41
42
43 class DiagramFactory:
44
45     @classmethod
46     def make_diagram(Class, width, height):
47         return Class.Diagram(width, height)
48
49
50     @classmethod
51     def make_rectangle(Class, x, y, width, height, fill="white",
52             stroke="black"):
53         return Class.Rectangle(x, y, width, height, fill, stroke)
54
55     @classmethod
56     def make_text(Class, x, y, text, fontsize=12):
57         return Class.Text(x, y, text, fontsize)
58
59
60     BLANK = " "
61     CORNER = "+"
62     HORIZONTAL = "-"
63     VERTICAL = "|"
64
65
66     class Diagram:
67
68         def __init__(self, width, height):
69             self.width = width
70             self.height = height
71             self.diagram = DiagramFactory._create_rectangle(self.width,
72                     self.height, DiagramFactory.BLANK)
73
74
75         def add(self, component):
76             for y, row in enumerate(component.rows):
77                 for x, char in enumerate(row):
78                     self.diagram[y + component.y][x + component.x] = char
79
80
81         def save(self, filenameOrFile):
82             file = (None if isinstance(filenameOrFile, str) else
83                     filenameOrFile)
84             try:
85                 if file is None:
86                     file = open(filenameOrFile, "w", encoding="utf-8")
87                 for row in self.diagram:
88                     print("".join(row), file=file)
89             finally:
90                 if isinstance(filenameOrFile, str) and file is not None:
91                     file.close()
92
93
94     class Rectangle:
95
96         def __init__(self, x, y, width, height, fill, stroke):
97             self.x = x
98             self.y = y
99             self.rows = DiagramFactory._create_rectangle(width, height,
100                     DiagramFactory.BLANK if fill == "white" else "%")
101
102
103     class Text:
104
105         def __init__(self, x, y, text, fontsize):
106             self.x = x
107             self.y = y
108             self.rows = [list(text)]
109
110
111     def _create_rectangle(width, height, fill):
112         rows = [[fill for _ in range(width)] for _ in range(height)]
113         for x in range(1, width - 1):
114             rows[0][x] = DiagramFactory.HORIZONTAL
115             rows[height - 1][x] = DiagramFactory.HORIZONTAL
116         for y in range(1, height - 1):
117             rows[y][0] = DiagramFactory.VERTICAL
118             rows[y][width - 1] = DiagramFactory.VERTICAL
119         for y, x in ((0, 0), (0, width - 1), (height - 1, 0),
120                 (height - 1, width -1)):
121             rows[y][x] = DiagramFactory.CORNER
122         return rows
123
124
125 class SvgDiagramFactory(DiagramFactory):
126
127     # The make_* class methods are inherited
128
129     SVG_START = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
130 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
131     "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
132 <svg xmlns="http://www.w3.org/2000/svg"
133     xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve"
134     width="{pxwidth}px" height="{pxheight}px">"""
135
136     SVG_END = "</svg>\n"
137
138     SVG_RECTANGLE = """<rect x="{x}" y="{y}" width="{width}" \
139 height="{height}" fill="{fill}" stroke="{stroke}"/>"""
140
141     SVG_TEXT = """<text x="{x}" y="{y}" text-anchor="left" \
142 font-family="sans-serif" font-size="{fontsize}">{text}</text>"""
143
144     SVG_SCALE = 20
145
146
147     class Diagram:
148
149         def __init__(self, width, height):
150             pxwidth = width * SvgDiagramFactory.SVG_SCALE
151             pxheight = height * SvgDiagramFactory.SVG_SCALE
152             self.diagram = [SvgDiagramFactory.SVG_START.format(**locals())]
153             outline = SvgDiagramFactory.Rectangle(0, 0, width, height,
154                     "lightgreen", "black")
155             self.diagram.append(outline.svg)
156
157
158         def add(self, component):
159             self.diagram.append(component.svg)
160
161
162         def save(self, filenameOrFile):
163             file = (None if isinstance(filenameOrFile, str) else
164                     filenameOrFile)
165             try:
166                 if file is None:
167                     file = open(filenameOrFile, "w", encoding="utf-8")
168                 file.write("\n".join(self.diagram))
169                 file.write("\n" + SvgDiagramFactory.SVG_END)
170             finally:
171                 if isinstance(filenameOrFile, str) and file is not None:
172                     file.close()
173
174
175     class Rectangle:
176
177         def __init__(self, x, y, width, height, fill, stroke):
178             x *= SvgDiagramFactory.SVG_SCALE
179             y *= SvgDiagramFactory.SVG_SCALE
180             width *= SvgDiagramFactory.SVG_SCALE
181             height *= SvgDiagramFactory.SVG_SCALE
182             self.svg = SvgDiagramFactory.SVG_RECTANGLE.format(**locals())
183
184
185     class Text:
186
187         def __init__(self, x, y, text, fontsize):
188             x *= SvgDiagramFactory.SVG_SCALE
189             y *= SvgDiagramFactory.SVG_SCALE
190             fontsize *= SvgDiagramFactory.SVG_SCALE // 10
191             self.svg = SvgDiagramFactory.SVG_TEXT.format(**locals())
192
193
194 if __name__ == "__main__":
195     main()


diagram2
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐