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


    注:关乎对象的创建方式的设计模式就是“创建型设计模式”(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     def make_diagram(self, width, height):
     46         return Diagram(width, height)
     47 
     48 
     49     def make_rectangle(self, x, y, width, height, fill="white",
     50             stroke="black"):
     51         return Rectangle(x, y, width, height, fill, stroke)
     52 
     53 
     54     def make_text(self, x, y, text, fontsize=12):
     55         return Text(x, y, text, fontsize)
     56 
     57 
     58 
     59 class SvgDiagramFactory(DiagramFactory):
     60 
     61     def make_diagram(self, width, height):
     62         return SvgDiagram(width, height)
     63 
     64 
     65     def make_rectangle(self, x, y, width, height, fill="white",
     66             stroke="black"):
     67         return SvgRectangle(x, y, width, height, fill, stroke)
     68 
     69 
     70     def make_text(self, x, y, text, fontsize=12):
     71         return SvgText(x, y, text, fontsize)
     72 
     73 
     74 BLANK = " "
     75 CORNER = "+"
     76 HORIZONTAL = "-"
     77 VERTICAL = "|"
     78 
     79 
     80 class Diagram:
     81 
     82     def __init__(self, width, height):
     83         self.width = width
     84         self.height = height
     85         self.diagram = _create_rectangle(self.width, self.height, BLANK)
     86 
     87 
     88     def add(self, component):
     89         for y, row in enumerate(component.rows):
     90             for x, char in enumerate(row):
     91                 self.diagram[y + component.y][x + component.x] = char
     92 
     93 
     94     def save(self, filenameOrFile):
     95         file = None if isinstance(filenameOrFile, str) else filenameOrFile
     96         try:
     97             if file is None:
     98                 file = open(filenameOrFile, "w", encoding="utf-8")
     99             for row in self.diagram:
    100                 print("".join(row), file=file)
    101         finally:
    102             if isinstance(filenameOrFile, str) and file is not None:
    103                 file.close()
    104 
    105 
    106 def _create_rectangle(width, height, fill):
    107     rows = [[fill for _ in range(width)] for _ in range(height)]
    108     for x in range(1, width - 1):
    109         rows[0][x] = HORIZONTAL
    110         rows[height - 1][x] = HORIZONTAL
    111     for y in range(1, height - 1):
    112         rows[y][0] = VERTICAL
    113         rows[y][width - 1] = VERTICAL
    114     for y, x in ((0, 0), (0, width - 1), (height - 1, 0),
    115             (height - 1, width -1)):
    116         rows[y][x] = CORNER
    117     return rows
    118 
    119 
    120 class Rectangle:
    121 
    122     def __init__(self, x, y, width, height, fill, stroke):
    123         self.x = x
    124         self.y = y
    125         self.rows = _create_rectangle(width, height,
    126                 BLANK if fill == "white" else "%")
    127 
    128 
    129 class Text:
    130 
    131     def __init__(self, x, y, text, fontsize):
    132         self.x = x
    133         self.y = y
    134         self.rows = [list(text)]
    135 
    136 
    137 SVG_START = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
    138 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
    139     "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
    140 <svg xmlns="http://www.w3.org/2000/svg"
    141     xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve"
    142     width="{pxwidth}px" height="{pxheight}px">"""
    143 
    144 SVG_END = "</svg>
    "
    145 
    146 SVG_RECTANGLE = """<rect x="{x}" y="{y}" width="{width}" 
    147 height="{height}" fill="{fill}" stroke="{stroke}"/>"""
    148 
    149 SVG_TEXT = """<text x="{x}" y="{y}" text-anchor="left" 
    150 font-family="sans-serif" font-size="{fontsize}">{text}</text>"""
    151 
    152 SVG_SCALE = 20
    153 
    154 
    155 class SvgDiagram:
    156 
    157 
    158     def __init__(self, width, height):
    159         pxwidth = width * SVG_SCALE
    160         pxheight = height * SVG_SCALE
    161         self.diagram = [SVG_START.format(**locals())]
    162         outline = SvgRectangle(0, 0, width, height, "lightgreen", "black")
    163         self.diagram.append(outline.svg)
    164 
    165 
    166     def add(self, component):
    167         self.diagram.append(component.svg)
    168 
    169 
    170     def save(self, filenameOrFile):
    171         file = None if isinstance(filenameOrFile, str) else filenameOrFile
    172         try:
    173             if file is None:
    174                 file = open(filenameOrFile, "w", encoding="utf-8")
    175             file.write("
    ".join(self.diagram))
    176             file.write("
    " + SVG_END)
    177         finally:
    178             if isinstance(filenameOrFile, str) and file is not None:
    179                 file.close()
    180 
    181 
    182 class SvgRectangle:
    183 
    184     def __init__(self, x, y, width, height, fill, stroke):
    185         x *= SVG_SCALE
    186         y *= SVG_SCALE
    187         width *= SVG_SCALE
    188         height *= SVG_SCALE
    189         self.svg = SVG_RECTANGLE.format(**locals())
    190 
    191 
    192 class SvgText:
    193 
    194     def __init__(self, x, y, text, fontsize):
    195         x *= SVG_SCALE
    196         y *= SVG_SCALE
    197         fontsize *= SVG_SCALE // 10
    198         self.svg = SVG_TEXT.format(**locals())
    199 
    200 
    201 if __name__ == "__main__":
    202     main()
    diagram1
      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>
    "
    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("
    ".join(self.diagram))
    169                 file.write("
    " + 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

                                            

  • 相关阅读:
    jmeter取样器
    【递归】普通递归关系
    7月,开始奋斗吧!
    BZOJ 1503 郁闷的出纳员
    bzoj 3262: 陌上花开
    BZOJ 2286 消耗战
    莫队
    bzoj1483: [HNOI2009]梦幻布丁
    字符串算法模板
    高级数据结构模板
  • 原文地址:https://www.cnblogs.com/HelloDreams/p/6382197.html
Copyright © 2020-2023  润新知