概述
用来创建复杂对象,这个复杂对象由许多小对象组成,这些小对象都属于某个特定的‘系列'
在GUI设计中可以设计一个“抽象控件工厂”,并射击三个“具体子类工厂”,
这三个具体的子类工厂分别为:MacWidgetFactory,XfaceWidgetFactory,WindowsWidgetFactory。他们属于同一系列(控件创建者),所以他们提供相同的chaugnjaing对象的方法(例如都提供make_button()创建按钮,change_position()指定控件的位置)。这三个具体的子类工厂将创建特定风格的控件,第一个是OS X风格,第二个是Linux风格,第三个是Windows风格。
因为这三个具体的子类都提供了相同的创建与修改方法,我们可以编写create_dialog()方法创建控件(该方法传入参数为三个具体工厂类中的一个),这样就可以通过传入create_dialog()的具体工厂类创建出具体风格的控件。
以下为伪代码(三个具体子类通过继承确认了统一套接口方法):
class MacWidgetFactory:
def make_button(self):
print('make_button_mac')
pass
def change_position(self):
print('change_position_max')
pass
class XfaceWidgetFactory(MacWidgetFactory):
def make_button(self):
print('maxk_button_linux')
pass
def change_position(self):
print('change_position_linux')
pass
class WindowsWidgetFactory(MacWidgetFactory):
def make_button(self):
print('window_button_windows')
pass
def change_position(self):
print('change_position_windows')
pass
def create_dialog(factory):
return factory.make_button().change_position()
下面看两个具体实现:
1.抽象工厂模式版本一
import os
def main():
textFilename=os.path.join("./",'text_diagram.txt')
txtDiagrm=create_diagram(DiagramFactory())
txtDiagrm.save(textFilename)
print('wrote:{}'.format(textFilename))
svgFilename=os.path.join('./','svg_diagram.svg')
svgDiagram=create_diagram(SvgDiagramFactory())
svgDiagram.save(svgFilename)
print('wrote:{}'.format(svgFilename))
def create_diagram(factory):
diagram=factory.make_diagram(30,7)
rectangle=factory.make_rectangle(4,1,22,5,'yellow')
text=factory.make_text(7,3,'Abstract Factory')
diagram.add(rectangle)
diagram.add(text)
return diagram
class DiagramFactory:
def make_diagram(self,width,height):
return Diagram(width,height)
def make_rectangle(self, x, y, width, height, fill="white",
stroke="black"):
return Rectangle(x, y, width, height, fill, stroke)
def make_text(self, x, y, text, fontsize=12):
return Text(x, y, text, fontsize)
class SvgDiagramFactory(DiagramFactory):
def make_diagram(self,width,height):
return SvgDiagram(width,height)
def make_rectangle(self, x, y, width, height, fill="white",
stroke="black"):
return SvgRectangle(x,y,width,height,fill,stroke)
def make_text(self,x,y,text,fontsize=12):
return SvgText(x,y,text,fontsize)
BLANK = " "
CORNER = "+"
HORIZONTAL = "-"
VERTICAL = "|"
class Diagram:
def __init__(self,width,height):
self.width = width
self.height = height
self.diagram = _create_rectangle(self.width, self.height, BLANK)
def add(self,component):
for y, row in enumerate(component.rows):
for x, char in enumerate(row):
self.diagram[y + component.y][x + component.x] = char
def save(self,filenameOrFile):
file = None if isinstance(filenameOrFile, str) else filenameOrFile
try:
if file is None:
file = open(filenameOrFile, "w", encoding="utf-8")
for row in self.diagram:
print("".join(row), file=file)
finally:
if isinstance(filenameOrFile, str) and file is not None:
file.close()
def _create_rectangle(width,height,fill):
rows = [[fill for _ in range(width)] for _ in range(height)]
for x in range(1, width - 1):
rows[0][x] = HORIZONTAL
rows[height - 1][x] = HORIZONTAL
for y in range(1, height - 1):
rows[y][0] = VERTICAL
rows[y][width - 1] = VERTICAL
for y, x in ((0, 0), (0, width - 1), (height - 1, 0),
(height - 1, width - 1)):
rows[y][x] = CORNER
return rows
class Rectangle:
def __init__(self,x,y,width,height,fill,stroke):
self.x = x
self.y = y
self.rows = _create_rectangle(width, height,
BLANK if fill == "white" else "%")
class Text:
def __init__(self,x,y,text,fontsize):
self.x = x
self.y = y
self.rows = [list(text)]
SVG_START = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve"
width="{pxwidth}px" height="{pxheight}px">"""
SVG_END = "</svg>\n"
SVG_RECTANGLE = """<rect x="{x}" y="{y}" width="{width}" \
height="{height}" fill="{fill}" stroke="{stroke}"/>"""
SVG_TEXT = """<text x="{x}" y="{y}" text-anchor="left" \
font-family="sans-serif" font-size="{fontsize}">{text}</text>"""
SVG_SCALE = 20
class SvgDiagram:
def __init__(self,width,height):
pxwidth = width * SVG_SCALE
pxheight = height * SVG_SCALE
self.diagram = [SVG_START.format(**locals())]
outline = SvgRectangle(0, 0, width, height, "lightgreen", "black")
self.diagram.append(outline.svg)
def add(self,component):
self.diagram.append(component.svg)
def save(self,filenameOrFile):
file=None if isinstance(filenameOrFile,str) else filenameOrFile
try:
if file is None:
file = open(filenameOrFile, "w", encoding="utf-8")
file.write("\n".join(self.diagram))
file.write("\n" + SVG_END)
finally:
if isinstance(filenameOrFile, str) and file is not None:
file.close()
class SvgRectangle:
def __init__(self,x,y,width,height,fill,stroke):
x *= SVG_SCALE
y *= SVG_SCALE
width *= SVG_SCALE
height *= SVG_SCALE
self.svg = SVG_RECTANGLE.format(**locals())
class SvgText:
def __init__(self, x, y, text, fontsize):
x *= SVG_SCALE
y *= SVG_SCALE
fontsize *= SVG_SCALE // 10
self.svg = SVG_TEXT.format(**locals())
if __name__=="__main__":
main()
2.抽象工厂模式版本二
import os
def main():
textFilename=os.path.join("./",'text_diagram.txt')
txtDiagrm=create_diagram(DiagramFactory)
txtDiagrm.save(textFilename)
print('wrote:{}'.format(textFilename))
svgFilename=os.path.join('./','svg_diagram.svg')
svgDiagram=create_diagram(SvgDiagramFactory)
svgDiagram.save(svgFilename)
print('wrote:{}'.format(svgFilename))
def create_diagram(factory):
diagram=factory.make_diagram(30,7)
rectangle=factory.make_rectangle(4,1,22,5,'yellow')
text=factory.make_text(7,3,'Abstract Factory')
diagram.add(rectangle)
diagram.add(text)
return diagram
class DiagramFactory:
@classmethod
def make_diagram(cls,width,height):
return cls.Diagram(width,height)
@classmethod
def make_rectangle(cls,x,y,width,height,fill='white',stroke='black'):
return cls.Rectangle(x,y,width,height,fill,stroke)
@classmethod
def make_text(cls,x,y,text,fontsize=12):
return cls.Text(x,y,text,fontsize)
BLANK=' '
CORNER='+'
HORIZONTAL='-'
VERTICAL='|'
class Diagram:
def __init__(self, width, height):
self.width = width
self.height = height
self.diagram = DiagramFactory._create_rectangle(self.width,
self.height, DiagramFactory.BLANK)
def add(self, component):
for y, row in enumerate(component.rows):
for x, char in enumerate(row):
self.diagram[y + component.y][x + component.x] = char
def save(self, filenameOrFile):
file = (None if isinstance(filenameOrFile, str) else
filenameOrFile)
try:
if file is None:
file = open(filenameOrFile, "w", encoding="utf-8")
for row in self.diagram:
print("".join(row), file=file)
finally:
if isinstance(filenameOrFile, str) and file is not None:
file.close()
class Rectangle:
def __init__(self, x, y, width, height, fill, stroke):
self.x = x
self.y = y
self.rows = DiagramFactory._create_rectangle(width, height,
DiagramFactory.BLANK if fill == "white" else "%")
class Text:
def __init__(self, x, y, text, fontsize):
self.x = x
self.y = y
self.rows = [list(text)]
@staticmethod
def _create_rectangle(width,height,fill):
rows = [[fill for _ in range(width)] for _ in range(height)]
for x in range(1, width - 1):
rows[0][x] = DiagramFactory.HORIZONTAL
rows[height - 1][x] = DiagramFactory.HORIZONTAL
for y in range(1, height - 1):
rows[y][0] = DiagramFactory.VERTICAL
rows[y][width - 1] = DiagramFactory.VERTICAL
for y, x in ((0, 0), (0, width - 1), (height - 1, 0),
(height - 1, width - 1)):
rows[y][x] = DiagramFactory.CORNER
return rows
class SvgDiagramFactory(DiagramFactory):
SVG_START="""<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve"
width="{pxwidth}px" height="{pxheight}px">"""
SVG_END="</svg>\n"
SVG_RECTANGLE="""<rect x="{x}" y="{y}" width="{width}" \
height="{height}" fill="{fill}" stroke="{stroke}"/>"""
SVG_TEXT="""<text x="{x}" y="{y}" text-anchor="left" \
font-family="sans-serif" font-size="{fontsize}">{text}</text>"""
SVG_SCALE=20
class Diagram:
def __init__(self, width, height):
pxwidth = width * SvgDiagramFactory.SVG_SCALE
pxheight = height * SvgDiagramFactory.SVG_SCALE
self.diagram = [SvgDiagramFactory.SVG_START.format(**locals())]
outline = SvgDiagramFactory.Rectangle(0, 0, width, height,
"lightgreen", "black")
self.diagram.append(outline.svg)
def add(self, component):
self.diagram.append(component.svg)
def save(self, filenameOrFile):
file = (None if isinstance(filenameOrFile, str) else
filenameOrFile)
try:
if file is None:
file = open(filenameOrFile, "w", encoding="utf-8")
file.write("\n".join(self.diagram))
file.write("\n" + SvgDiagramFactory.SVG_END)
finally:
if isinstance(filenameOrFile, str) and file is not None:
file.close()
class Rectangle:
def __init__(self,x,y,width,height,fill,stroke):
x *= SvgDiagramFactory.SVG_SCALE
y *= SvgDiagramFactory.SVG_SCALE
width *= SvgDiagramFactory.SVG_SCALE
height *= SvgDiagramFactory.SVG_SCALE
self.svg = SvgDiagramFactory.SVG_RECTANGLE.format(**locals())
class Text:
def __init__(self,x,y,text,fontsize):
x *= SvgDiagramFactory.SVG_SCALE
y *= SvgDiagramFactory.SVG_SCALE
fontsize *= SvgDiagramFactory.SVG_SCALE // 10
self.svg = SvgDiagramFactory.SVG_TEXT.format(**locals())
if __name__=="__main__":
main()