zoukankan      html  css  js  c++  java
  • python设计模式

    软件工程中,设计模式是指软件设计问题的推荐方案。设计模式一般是描述如何组织代码和 使用最佳实践来解决常见的设计问题。

    创建型模式,处理对象创建的设计模式.

    工厂模式

    工厂通常有两种形式:

    第一种是工厂方法(Factory Method),

    它是一个方法(Python 术语来说,是一个函数),对不同的输入参数返回不同的对象;

    示例中函数connection_factory是一个工厂方法,基于输入文件路径的扩展名返回一个 JSONConnector或XMLConnector的实例

    import xml.etree.ElementTree as etree
    import json
    
    
    class JSONConnector:
    
        def __init__(self, filepath):
            self.data = dict()
            with open(filepath, mode='r', encoding='utf-8') as f:
                self.data = json.load(f)
    
        @property
        def parsed_data(self):
            return self.data
    
    
    class XMLConnector:
    
        def __init__(self, filepath):
            self.tree = etree.parse(filepath)
    
        @property
        def parsed_data(self):
            return self.tree
    
    
    def connection_factory(filepath):
        if filepath.endswith('json'):
            connector = JSONConnector
        elif filepath.endswith('xml'):
            connector = XMLConnector
        else:
            raise ValueError('Cannot connect to {}'.format(filepath))
        return connector(filepath)
    
    
    def connect_to(filepath):
        factory = None
        try:
            factory = connection_factory(filepath)
        except ValueError as ve:
            print(ve)
        return factory
    
    
    def main():
        sqlite_factory = connect_to('data/person.sq3')
        print()
    
        xml_factory = connect_to('data/person.xml')
        xml_data = xml_factory.parsed_data
        liars = xml_data.findall(".//{}[{}='{}']".format('person',
                                                         'lastName', 'Liar'))
        print('found: {} persons'.format(len(liars)))
        for liar in liars:
            print('first name: {}'.format(liar.find('firstName').text))
            print('last name: {}'.format(liar.find('lastName').text))
            [print('phone number ({})'.format(p.attrib['type']),
                   p.text) for p in liar.find('phoneNumbers')]
    
        print()
    
        json_factory = connect_to('data/donut.json')
        json_data = json_factory.parsed_data
        print('found: {} donuts'.format(len(json_data)))
        for donut in json_data:
            print('name: {}'.format(donut['name']))
            print('price: ${}'.format(donut['ppu']))
            [print('topping: {} {}'.format(t['id'], t['type'])) for t in donut['topping']]
    
    if __name__ == '__main__':
        main()
    factory_method.py

    第二种是抽象工厂,

    它是一组用于创建一系列相关事物对象的工厂方法。是工厂方法模式的一种泛化,应用需要许多工厂方法,那么将创建一系列对象的过程合并在一起。

    示例中main()函数,该函数请求用户的姓名和年龄,并根据用户的年龄决定该玩哪个游戏。

    # Author:song
    class Frog:
    
        def __init__(self, name):
            self.name = name
    
        def __str__(self):
            return self.name
    
        def interact_with(self, obstacle):
            print('{} the Frog encounters {} and {}!'.format(self,
                                                             obstacle, obstacle.action()))
    
    
    class Bug:
    
        def __str__(self):
            return 'a bug'
    
        def action(self):
            return 'eats it'
    
    
    class FrogWorld:
            """抽象工厂,其主要职责是创建游戏的主人公和障碍物"""
        def __init__(self, name):
            print(self)
            self.player_name = name
    
        def __str__(self):
            return '
    
    	------ Frog World ———'
    
        def make_character(self):
            return Frog(self.player_name)
    
        def make_obstacle(self):
            return Bug()
    
    
    class Wizard:
    
        def __init__(self, name):
            self.name = name
    
        def __str__(self):
            return self.name
    
        def interact_with(self, obstacle):
            print('{} the Wizard battles against {} and {}!'.format(self, obstacle, obstacle.action()))
    
    
    class Ork:
    
        def __str__(self):
            return 'an evil ork'
    
        def action(self):
            return 'kills it'
    
    
    class WizardWorld:
        """抽象工厂,其主要职责是创建游戏的主人公和障碍物"""
        def __init__(self, name):
            print(self)
            self.player_name = name
    
        def __str__(self):
            return '
    
    	------ Wizard World ———'
    
        def make_character(self):
            return Wizard(self.player_name)
    
        def make_obstacle(self):
            return Ork()
    
    
    class GameEnvironment:
    
        def __init__(self, factory):
            self.hero = factory.make_character()
            self.obstacle = factory.make_obstacle()
    
        def play(self):
            self.hero.interact_with(self.obstacle)
    
    
    def validate_age(name):
        try:
            age = input('Welcome {}. How old are you? '.format(name))
            age = int(age)
        except ValueError as err:
            print("Age {} is invalid, please try 
            again…".format(age))
            return (False, age)
        return (True, age)
    
    
    def main():
        name = input("Hello. What's your name? ")
        valid_input = False
        while not valid_input:
            valid_input, age = validate_age(name)
        game = FrogWorld if age < 18 else WizardWorld
        environment = GameEnvironment(game(name))
        environment.play()
    
    if __name__ == '__main__':
        main()
    abstract_method.py

    建造者设计模式

    将一个复杂对象的构造过程与其表现分离,如果我们知道一个对象必须经过多个步骤来创建,并且要求同一个构造过程可以产生不同的表现,就可以使用建造者模式。

    # Author:song
    # coding: utf-8
    
    
    class Computer:
    
        def __init__(self, serial_number):
            self.serial = serial_number
            self.memory = None      # 单位为GB
            self.hdd = None         # 单位为GB
            self.gpu = None
    
        def __str__(self):
            info = ('Memory: {}GB'.format(self.memory),
                    'Hard Disk: {}GB'.format(self.hdd),
                    'Graphics Card: {}'.format(self.gpu))
            return '
    '.join(info)
    
    
    class ComputerBuilder:
    
        def __init__(self):
            self.computer = Computer('AG23385193')
    
        def configure_memory(self, amount):
            self.computer.memory = amount
    
        def configure_hdd(self, amount):
            self.computer.hdd = amount
    
        def configure_gpu(self, gpu_model):
            self.computer.gpu = gpu_model
    
    
    class HardwareEngineer:
    
        def __init__(self):
            self.builder = None
    
        def construct_computer(self, memory, hdd, gpu):
            self.builder = ComputerBuilder()
            [step for step in (self.builder.configure_memory(memory),
                               self.builder.configure_hdd(hdd),
                               self.builder.configure_gpu(gpu))]
    
        @property
        def computer(self):
            return self.builder.computer
    
    
    def main():
        engineer = HardwareEngineer()
        engineer.construct_computer(hdd=500, memory=8, gpu='GeForce GTX 650 Ti')
        computer = engineer.computer
        print(computer)
    
    if __name__ == '__main__':
        main()
    builder.py

    原型设计模式

    无非就是克隆一个对象。原始对象的所有数据都被简单地复制到克隆对象中,用于创建对象的完全副本。示例图书信息版本信息,是深拷贝,旨在创建新对象而不影响原先数据

    # Author:song
    # coding: utf-8
    
    import copy
    from collections import OrderedDict
    
    
    class Book:
    
        def __init__(self, name, authors, price, **rest):
            '''rest的例子有:出版商,长度,标签,出版日期'''
            self.name = name
            self.authors = authors
            self.price = price
            self.__dict__.update(rest)
    
        def __str__(self):
            mylist = []
            ordered = OrderedDict(sorted(self.__dict__.items()))
            for i in ordered.keys():
                mylist.append('{}: {}'.format(i, ordered[i]))
                if i == 'price':
                    mylist.append('$')
                mylist.append('
    ')
            return ''.join(mylist)
    
    
    class Prototype:
    
        def __init__(self):
            self.objects = dict()
    
        def register(self, identifier, obj):
            self.objects[identifier] = obj
    
        def unregister(self, identifier):
            del self.objects[identifier]
    
        def clone(self, identifier, **attr):
            found = self.objects.get(identifier)
            if not found:
                raise ValueError('Incorrect object identifier: {}'.format(identifier))
            obj = copy.deepcopy(found)
            obj.__dict__.update(attr)
            return obj
    
    
    def main():
        b1 = Book('The C Programming Language', ('Brian W. Kernighan', 'Dennis M.Ritchie'), price=118, publisher='Prentice Hall',
                  length=228, publication_date='1978-02-22', tags=('C', 'programming', 'algorithms', 'data structures'))
    
        prototype = Prototype()
        cid = 'k&r-first'
        prototype.register(cid, b1)
        b2 = prototype.clone(cid, name='The C Programming Language(ANSI)', price=48.99,
                             length=274, publication_date='1988-04-01', edition=2)
    
        for i in (b1, b2):
            print(i)
        print('ID b1 : {} != ID b2 : {}'.format(id(b1), id(b2)))
    
    if __name__ == '__main__':
        main()
    prototype.py

    结构型模式,介绍处理一个系统中不同实体(类、对象等)之间关系的设计模式,关注的是提供一 种简单的对象组合方式来创造新功能.

    适配器模式(Adapter pattern)

    是一种结构型设计模式,帮助我们实现两个不兼容接口之间的兼容,无需修改不兼容模型的源代码就能获得接口的 一致性

    """。在Synthesizer类中,主要动作由play()方法执行。在Human类中,主要动作由speak()方法执行,客户端仅知道如何调用execute()方法,并不知道play()和speak()。在不改变Synthesizer和Human类的前提运行代码"""
    
    
    class Synthesizer:
    
        def __init__(self, name):
            self.name = name
    
        def __str__(self):
            return 'the {} synthesizer'.format(self.name)
    
        def play(self):
            return 'is playing an electronic song'
    
    
    class Human:
    
        def __init__(self, name):
            self.name = name
    
        def __str__(self):
            return '{} the human'.format(self.name)
    
        def speak(self):
            return 'says hello'
    
    
    
    class Computer:
        def __init__(self, name):
            self.name = name
    
        def __str__(self):
            return 'the {} computer'.format(self.name)
    
        def execute(self):
            return 'executes a program'
    
    
    class Adapter:
    
        def __init__(self, obj, adapted_methods):
            self.obj = obj
            self.__dict__.update(adapted_methods)
    
        def __str__(self):
            return str(self.obj)
    
    
    def main():
        objects = [Computer('Asus')]
        synth = Synthesizer('moog')
        objects.append(Adapter(synth, dict(execute=synth.play)))
        human = Human('Bob')
        objects.append(Adapter(human, dict(execute=human.speak)))
    
        for i in objects:
            print('{} {}'.format(str(i), i.execute()))
    
    if __name__ == "__main__":
        main()
    Adapter_pattern.py

    修饰器(Decorator)模式

    能够以透明的方式(不会影响其他对象)动态地将功能添加到一个对象中。

    # Author:song
    # coding: utf-8
    
    import functools
    
    
    def memoize(fn):
        known = dict()
    
        @functools.wraps(fn)
        def memoizer(*args):
            if args not in known:
                known[args] = fn(*args)
            return known[args]
    
        return memoizer
    
    
    @memoize
    def nsum(n):
        '''返回前n个数字的和'''
        assert(n >= 0), 'n must be >= 0'
        return 0 if n == 0 else n + nsum(n-1)
    
    
    @memoize
    def fibonacci(n):
        '''返回斐波那契数列的第n个数'''
        assert(n >= 0), 'n must be >= 0'
        return n if n in (0, 1) else fibonacci(n-1) + fibonacci(n-2)
    
    if __name__ == '__main__':
        from timeit import Timer
        measure = [{'exec': 'fibonacci(100)', 'import': 'fibonacci',
                    'func': fibonacci}, {'exec': 'nsum(200)', 'import': 'nsum',
                                         'func': nsum}]
        for m in measure:
            t = Timer('{}'.format(m['exec']), 'from __main__ import 
                {}'.format(m['import']))
            print('name: {}, doc: {}, executing: {}, time: 
                {}'.format(m['func'].__name__, m['func'].__doc__,
                           m['exec'], t.timeit()))
    mymath.py

     外观设计模式

    有助于隐藏系统的内部复杂性,并通过一个简化的接口向客户端暴露必要的部分,本质上,外观(Facade)是在已有复杂系统之上实现的一个抽象层。这种模式是为复杂系统提供一个简单接口的理想方式

    from enum import Enum
    from abc import ABCMeta, abstractmethod
    
    State = Enum('State', 'new running sleeping restart zombie')
    
    
    class User:
        pass
    
    
    class Process:
        pass
    
    
    class File:
        pass
    
    
    class Server(metaclass=ABCMeta):
    
        @abstractmethod
        def __init__(self):
            pass
    
        def __str__(self):
            return self.name
    
        @abstractmethod
        def boot(self):
            pass
    
        @abstractmethod
        def kill(self, restart=True):
            pass
    
    
    class FileServer(Server):
    
        def __init__(self):
            '''初始化文件服务进程要求的操作'''
            self.name = 'FileServer'
            self.state = State.new
    
        def boot(self):
            print('booting the {}'.format(self))
            '''启动文件服务进程要求的操作'''
            self.state = State.running
    
        def kill(self, restart=True):
            print('Killing {}'.format(self))
            '''杀死文件服务进程要求的操作'''
            self.state = State.restart if restart else State.zombie
    
        def create_file(self, user, name, permissions):
            '''检查访问权限的有效性、用户权限,等等'''
    
            print("trying to create the file '{}' for user '{}' with permissions {}".format(name, user, permissions))
    
    
    class ProcessServer(Server):
    
        def __init__(self):
            '''初始化进程服务进程要求的操作'''
            self.name = 'ProcessServer'
            self.state = State.new
    
        def boot(self):
            print('booting the {}'.format(self))
            '''启动进程服务进程要求的操作'''
            self.state = State.running
    
        def kill(self, restart=True):
            print('Killing {}'.format(self))
            '''杀死进程服务进程要求的操作'''
            self.state = State.restart if restart else State.zombie
    
        def create_process(self, user, name):
            '''检查用户权限、生成PID,等等'''
    
            print("trying to create the process '{}' for user '{}'".format(name, user))
    
    
    class WindowServer:
        pass
    
    
    class NetworkServer:
        pass
    
    
    class OperatingSystem:
    
        '''外观'''
    
        def __init__(self):
            self.fs = FileServer()
            self.ps = ProcessServer()
    
        def start(self):
            [i.boot() for i in (self.fs, self.ps)]
    
        def create_file(self, user, name, permissions):
            return self.fs.create_file(user, name, permissions)
    
        def create_process(self, user, name):
            return self.ps.create_process(user, name)
    
    
    def main():
        os = OperatingSystem()
        os.start()
        os.create_file('foo', 'hello', '-rw-r-r')
        os.create_process('bar', 'ls /tmp')
    
    if __name__ == '__main__':
        main()
    facade.py

    享元设计模式

    通过为相似对象引入数据共享来最小化内存使用,旨在优化性能和内存使用,一个享元(Flyweight)就是一个包含状态独立的不可变(又称固有的)数据的 共享对象。依赖状态的可变(又称非固有的)数据不应是享元的一部分,因为每个对象的这种信 息都不同,无法共享。

    # coding: utf-8
    
    import random
    from enum import Enum
    
    TreeType = Enum('TreeType', 'apple_tree cherry_tree peach_tree')
    
    
    class Tree:
        pool = dict()
    
        def __new__(cls, tree_type):
            obj = cls.pool.get(tree_type, None)
            if not obj:
                obj = object.__new__(cls)
                cls.pool[tree_type] = obj
                obj.tree_type = tree_type
            return obj
    
        def render(self, age, x, y):
            print('render a tree of type {} and age {} at ({}, {})'.format(self.tree_type, age, x, y))
    
    
    def main():
        rnd = random.Random()
        age_min, age_max = 1, 30    # 单位为年
        min_point, max_point = 0, 100
        tree_counter = 0
    
        for _ in range(10):
            t1 = Tree(TreeType.apple_tree)
            t1.render(rnd.randint(age_min, age_max),
                      rnd.randint(min_point, max_point),
                      rnd.randint(min_point, max_point))
            tree_counter += 1
    
        for _ in range(3):
            t2 = Tree(TreeType.cherry_tree)
            t2.render(rnd.randint(age_min, age_max),
                      rnd.randint(min_point, max_point),
                      rnd.randint(min_point, max_point))
            tree_counter += 1
    
        for _ in range(5):
            t3 = Tree(TreeType.peach_tree)
            t3.render(rnd.randint(age_min, age_max),
                      rnd.randint(min_point, max_point),
                      rnd.randint(min_point, max_point))
            tree_counter += 1
    
        print('trees rendered: {}'.format(tree_counter))
        print('trees actually created: {}'.format(len(Tree.pool)))
    
        t4 = Tree(TreeType.cherry_tree)
        t5 = Tree(TreeType.cherry_tree)
        t6 = Tree(TreeType.apple_tree)
        print('{} == {}? {}'.format(id(t4), id(t5), id(t4) == id(t5)))
        print('{} == {}? {}'.format(id(t5), id(t6), id(t5) == id(t6)))
    
    if __name__ == '__main__':
        main()
    flyweight

    模型—视图—控制器(Model-View-Controller,MVC)模式

    模型—视图—控制器(Model-View-Controller,MVC)模式是应用到面向对象编程的Soc原则。 模式的名称来自用来切分软件应用的三个主要部分,即模型部分、视图部分和控制器部分。MVC 被认为是一种架构模式而不是一种设计模式。架构模式与设计模式之间的区别在于前者比后者的范畴更广

    # Author:song
    quotes = ('A man is not complete until he is married. Then he is finished.',
              'As I said before, I never repeat myself.',
              'Behind a successful man is an exhausted woman.',
              'Black holes really suck...', 'Facts are stubborn things.')
    
    
    class QuoteModel:
        """模型极为简约,只有一个get_quote()方法,基于索引n从quotes元组中返回对应的名人
    名言(字符串)"""
    
        def get_quote(self, n):
            try:
                value = quotes[n]
            except IndexError as err:
                value = 'Not found!'
            return value
    
    
    class QuoteTerminalView:
        """视图有三个方法,分别是show()、error()和select_quote()。show()用于在屏幕上输
    出一句名人名言(或者输出提示信息Not found!);error()用于在屏幕上输出一条错误消息;
    select_quote()用于读取用户的选择"""
    
        def show(self, quote):
            print('And the quote is: "{}"'.format(quote))
    
        def error(self, msg):
            print('Error: {}'.format(msg))
    
        def select_quote(self):
            return input('Which quote number would you like to see?')
    
    
    class QuoteTerminalController:
        """控制器负责协调。__init__()方法初始化模型和视图。run()方法校验用户提供的名言索
    引,然后从模型中获取名言,并返回给视图展示"""0
        def __init__(self):
            self.model = QuoteModel()
            self.view = QuoteTerminalView()
    
        def run(self):
            valid_input = False
            while not valid_input:
                n = self.view.select_quote()
                try:
                    n = int(n)
                except ValueError as err:
                    self.view.error("Incorrect index '{}'".format(n))
                else:
                    valid_input = True
            quote = self.model.get_quote(n)
            self.view.show(quote)
    
    
    def main():
        controller = QuoteTerminalController()
        while True:
            controller.run()
    
    if __name__ == '__main__':
        main()
    mvc.py

    代理设计模式(Proxy design pattern)

    访问某个对象之前执行一个或多个重要的操作。对象在访问实际对象之前执行重要操作而得其名。

    使用代理模式实现一个实际类的替代品,这 样可以在访问实际类之前(或之后)做一些额外的事情。四个不同类型

      远程代理,代表一个活跃于远程位置(例如,我们自己的远程服务器或云服务)的对象。

     虚拟代理,将一个对象的初始化延迟到真正需要使用时进行。

     保护/防护代理,用于对处理敏感信息的对象进行访问控制。

     当我们希望通过添加帮助信息(比如,引用计数)来扩展一个对象的行为时,可以使用 智能(引用)代理。

    # Author:song
    class SensitiveInfo:
    
        def __init__(self):
            self.users = ['nick', 'tom', 'ben', 'mike']
    
        def read(self):
            print('There are {} users: {}'.format(len(self.users), ' '.join(self.users)))
    
        def add(self, user):
            self.users.append(user)
            print('Added user {}'.format(user))
    
    
    class Info:
    
        '''SensitiveInfo的保护代理'''
    
        def __init__(self):
            self.protected = SensitiveInfo()
            self.secret = '0xdeadbeef'
    
        def read(self):
            self.protected.read()
    
        def add(self, user):
            sec = input('what is the secret? ')
            self.protected.add(user) if sec == self.secret else print("That's wrong!")
    
    
    def main():
        info = Info()
        while True:
            print('1. read list |==| 2. add user |==| 3. quit')
            key = input('choose option: ')
            if key == '1':
                info.read()
            elif key == '2':
                name = input('choose username: ')
                info.add(name)
            elif key == '3':
                exit()
            else:
                print('unknown option: {}'.format(key))
    
    if __name__ == '__main__':
        main()
    proxy.py

    行为型模式,介绍处理系统实体之间通信的设计模式

    责任链(Chain of Responsibility)模式

    用于让多个对象来处理单个请求 时,或者用于预先不知道应该由哪个对象(来自某个对象链)来处理某个特定请求时。

     可以使用广播计算机网络的类比来理解责任链模式

    # Author:song
    
    """
    MainWindow、MsgText和SendDialog是具有不同行为的控件,
    MainWindow仅能处理close和default事件,
    SendDialog仅能处理paint事件,
    MsgText仅能处理down事件
    main()函数展示如何创建一些控件和事件,以及控件如何对那些事件作出反应。
    所有事件都会被发送给所有控件
    """
    class Event:
    
        def __init__(self, name):
            self.name = name
    
        def __str__(self):
            return self.name
    
    
    class Widget:
    
        def __init__(self, parent=None):
            self.parent = parent
    
        def handle(self, event):
            """handle()方法使用动态分发,通过hasattr()和getattr()决定一个特定请求(event)
    应该由谁来处理。如果被请求处理事件的控件并不支持该事件,则有两种回退机制。如果控件有
    parent,则执行parent的handle()方法。如果控件没有parent,但有handle_default()方
    法,则执行handle_default()。"""
            handler = 'handle_{}'.format(event)
            if hasattr(self, handler):
                method = getattr(self, handler)
                method(event)
            elif self.parent:
                self.parent.handle(event)
            elif hasattr(self, 'handle_default'):
                self.handle_default(event)
    
    
    class MainWindow(Widget):
    
        def handle_close(self, event):
            print('MainWindow: {}'.format(event))
    
        def handle_default(self, event):
            print('MainWindow Default: {}'.format(event))
    
    
    class SendDialog(Widget):
    
        def handle_paint(self, event):
            print('SendDialog: {}'.format(event))
    
    
    class MsgText(Widget):
    
        def handle_down(self, event):
            print('MsgText: {}'.format(event))
    
    
    def main():
        mw = MainWindow()
        sd = SendDialog(mw)
        msg = MsgText(sd)
    
        for e in ('down', 'paint', 'unhandled', 'close'):
            evt = Event(e)
            print('
    Sending event -{}- to MainWindow'.format(evt))
            mw.handle(evt)
            print('Sending event -{}- to SendDialog'.format(evt))
            sd.handle(evt)
            print('Sending event -{}- to MsgText'.format(evt))
            msg.handle(evt)
    
    if __name__ == '__main__':
        main()
    chain.py

    命令设计模式

    帮助我们将一个操作(撤销、重做、复制、粘贴等)封装成一个对象。简而言之,这意味着创建一个类,包含实现该操作所需要的所有逻辑和方法.

    撤销操作确实是命令模式的杀手级特性。

    优势:

     我们并不需要直接执行一个命令。命令可以按照希望执行。

     调用命令的对象与知道如何执行命令的对象解耦。调用者无需知道命令的任何实现细节。

     如果有意义,可以把多个命令组织起来,这样调用者能够按顺序执行它们。例如,在实 现一个多层撤销命令时,这是很有用的。

    # Author:song
    import os
    
    verbose = True
    
    
    class RenameFile:
    
        def __init__(self, path_src, path_dest):
            self.src, self.dest = path_src, path_dest
    
        def execute(self):
            if verbose:
                print("[renaming '{}' to '{}']".format(self.src, self.dest))
            os.rename(self.src, self.dest)
    
        def undo(self):
            """通过undo()方法支持撤销操作。在这里,撤销操作再次使用os.rename()
    将文件名恢复为原始值。"""
            if verbose:
                print("[renaming '{}' back to '{}']".format(self.dest, self.src))
            os.rename(self.dest, self.src)
    
    
    class CreateFile:
        """。__init__()函数接受熟悉的
    path参数和一个txt字符串,默认向文件写入hello world文本"""
        def __init__(self, path, txt='hello world
    '):
            self.path, self.txt = path, txt
    
        def execute(self):
            if verbose:
                print("[creating file '{}']".format(self.path))
            with open(self.path, mode='w', encoding='utf-8') as out_file:
                out_file.write(self.txt)
    
        def undo(self):
            delete_file(self.path)
    
    
    class ReadFile:
    
        def __init__(self, path):
            self.path = path
    
        def execute(self):
            if verbose:
                print("[reading file '{}']".format(self.path))
            with open(self.path, mode='r', encoding='utf-8') as in_file:
                print(in_file.read(), end='')
    
    
    def delete_file(path):
        """数接受一个字符串类型的文件路
    径,并使用os.remove()来删除它"""
        if verbose:
            print("deleting file '{}'".format(path))
        os.remove(path)
    
    
    def main():
        """main()函数使用这些工具类/方法。参数orig_name和new_name是待创建文件的原始名称
    以及重命名后的新名称。commands列表用于添加(并配置)所有我们之后想要执行的命令。注
    意,命令不会被执行,除非我们显式地调用每个命令的execute()
    下一步是询问用户是否需要撤销执行过的命令。用户选择撤销命令或不撤销。如果选择撤销,
    则执行commands列表中所有命令的undo()。然而,由于并不是所有命令都支持撤销,因此在
    undo()方法不存在时产生的AttributeError异常要使用异常处理来捕获
    """
        orig_name, new_name = 'file1', 'file2'
    
        commands = []
        for cmd in CreateFile(orig_name), ReadFile(orig_name), RenameFile(orig_name, new_name):
            commands.append(cmd)
    
        [c.execute() for c in commands]
    
        answer = input('reverse the executed commands? [y/n] ')
    
        if answer not in 'yY':
            print("the result is {}".format(new_name))
            exit()
    
        for c in reversed(commands):
            try:
                c.undo()
            except AttributeError as e:
                pass
    
    if __name__ == '__main__':
        main()
    comment.py

    解释器(Interpreter)模式

    解释器模式仅能引起应用的高级用户的兴趣。这是因为解释器模式背后的主 要思想是让非初级用户和领域专家使用一门简单的语言来表达想法.

    解释器模式用于为高级用户和领域专家提供一个类编程的框架,但没有暴露出编程语言那样的复杂性.

    对每个应用来说,至少有以下两种不同的用户分类。

     基本用户:这类用户只希望能够凭直觉使用应用。他们不喜欢花太多时间配置或学习应 用的内部。对他们来说,基本的用法就足够了。

     高级用户:这些用户,实际上通常是少数,不介意花费额外的时间学习如何使用应用的 高级特性。如果知道学会之后能得到以下好处,他们甚至会去学习一种配置(或脚本) 语言。

    # Author:song
    # coding: utf-8
    """使用了Pyparsing创建一种
    DSL来控制一个智能屋,并且看到使用一个好的解析工具以模式匹配来解释结果更加简单"""
    from pyparsing import Word, OneOrMore, Optional, Group, Suppress, alphanums
    
    
    class Gate:
    
        def __init__(self):
            self.is_open = False
    
        def __str__(self):
            return 'open' if self.is_open else 'closed'
    
        def open(self):
            print('opening the gate')
            self.is_open = True
    
        def close(self):
            print('closing the gate')
            self.is_open = False
    
    
    class Garage:
    
        def __init__(self):
            self.is_open = False
    
        def __str__(self):
            return 'open' if self.is_open else 'closed'
    
        def open(self):
            print('opening the garage')
            self.is_open = True
    
        def close(self):
            print('closing the garage')
            self.is_open = False
    
    
    class Aircondition:
    
        def __init__(self):
            self.is_on = False
    
        def __str__(self):
            return 'on' if self.is_on else 'off'
    
        def turn_on(self):
            print('turning on the aircondition')
            self.is_on = True
    
        def turn_off(self):
            print('turning off the aircondition')
            self.is_on = False
    
    
    class Heating:
    
        def __init__(self):
            self.is_on = False
    
        def __str__(self):
            return 'on' if self.is_on else 'off'
    
        def turn_on(self):
            print('turning on the heating')
            self.is_on = True
    
        def turn_off(self):
            print('turning off the heating')
            self.is_on = False
    
    
    class Boiler:
    
        def __init__(self):
            self.temperature = 83  # in celsius
    
        def __str__(self):
            return 'boiler temperature: {}'.format(self.temperature)
    
        def increase_temperature(self, amount):
            print("increasing the boiler's temperature by {} degrees".format(amount))
            self.temperature += amount
    
        def decrease_temperature(self, amount):
            print("decreasing the boiler's temperature by {} degrees".format(amount))
            self.temperature -= amount
    
    
    class Fridge:
    
        def __init__(self):
            self.temperature = 2  # 单位为摄氏度
    
        def __str__(self):
            return 'fridge temperature: {}'.format(self.temperature)
    
        def increase_temperature(self, amount):
            print("increasing the fridge's temperature by {} degrees".format(amount))
            self.temperature += amount
    
        def decrease_temperature(self, amount):
            print("decreasing the fridge's temperature by {} degrees".format(amount))
            self.temperature -= amount
    
    
    def main():
        word = Word(alphanums)
        command = Group(OneOrMore(word))
        token = Suppress("->")
        device = Group(OneOrMore(word))
        argument = Group(OneOrMore(word))
        event = command + token + device + Optional(token + argument)
    
        gate = Gate()
        garage = Garage()
        airco = Aircondition()
        heating = Heating()
        boiler = Boiler()
        fridge = Fridge()
    
        tests = ('open -> gate',
                 'close -> garage',
                 'turn on -> aircondition',
                 'turn off -> heating',
                 'increase -> boiler temperature -> 5 degrees',
                 'decrease -> fridge temperature -> 2 degrees')
        open_actions = {'gate': gate.open,
                        'garage': garage.open,
                        'aircondition': airco.turn_on,
                        'heating': heating.turn_on,
                        'boiler temperature': boiler.increase_temperature,
                        'fridge temperature': fridge.increase_temperature}
        close_actions = {'gate': gate.close,
                         'garage': garage.close,
                         'aircondition': airco.turn_off,
                         'heating': heating.turn_off,
                         'boiler temperature': boiler.decrease_temperature,
                         'fridge temperature': fridge.decrease_temperature}
    
        for t in tests:
            if len(event.parseString(t)) == 2:  # 没有参数
                cmd, dev = event.parseString(t)
                cmd_str, dev_str = ' '.join(cmd), ' '.join(dev)
                if 'open' in cmd_str or 'turn on' in cmd_str:
                    open_actions[dev_str]()
                elif 'close' in cmd_str or 'turn off' in cmd_str:
                    close_actions[dev_str]()
            elif len(event.parseString(t)) == 3:  # 有参数
                cmd, dev, arg = event.parseString(t)
                cmd_str, dev_str, arg_str = ' '.join(cmd), ' '.join(dev), ' '.join(arg)
                num_arg = 0
                try:
                    num_arg = int(arg_str.split()[0])  # 抽取数值部分
                except ValueError as err:
                    print("expected number but got: '{}'".format(arg_str[0]))
                if 'increase' in cmd_str and num_arg > 0:
                    open_actions[dev_str](num_arg)
                elif 'decrease' in cmd_str and num_arg > 0:
                    close_actions[dev_str](num_arg)
    
    if __name__ == '__main__':
        main()
    interpreter.py

     

    观察者模式

    我们希望在一个对象的状态改变时更新另外一组对象,观察者模式描述单个对象(发布者,又称为主持者或可观察者)与一个或多个对象(订阅者, 又称为观察者)之间的发布—订阅关系。

    观察者模式背后的思想等同于MVC和关注点分离原则背后的思想,即降低发布者与订阅者 之间的耦合度,从而易于在运行时添加/删除订阅者。此外,发布者不关心它的订阅者是谁。它只是将通知发送给所有订阅者。

    若希望在一个对象的状态变化时能够通知/提醒所有 相关者(一个对象或一组对象),则可以使用观察者模式。观察者模式的一个重要特性是,在运行时,订阅者/观察者的数量以及观察者是谁可能会变化,也可以改变

    # Author:song
    class Publisher:
    
        def __init__(self):
            self.observers = []
    
        def add(self, observer):
            if observer not in self.observers:
                self.observers.append(observer)
            else:
                print('Failed to add: {}'.format(observer))
    
        def remove(self, observer):
            try:
                self.observers.remove(observer)
            except ValueError:
                print('Failed to remove: {}'.format(observer))
    
        def notify(self):
            [o.notify(self) for o in self.observers]
    
    
    class DefaultFormatter(Publisher):
    
        def __init__(self, name):
            Publisher.__init__(self)
            self.name = name
            self._data = 0
    
        def __str__(self):
            return "{}: '{}' has data = {}".format(type(self).__name__, self.name, self._data)
    
        @property
        def data(self):
            return self._data
    
        @data.setter
        def data(self, new_value):
            try:
                self._data = int(new_value)
            except ValueError as e:
                print('Error: {}'.format(e))
            else:
                self.notify()
    
    
    class HexFormatter:
    
        def notify(self, publisher):
            print("{}: '{}' has now hex data = {}".format(type(self).__name__,
                                                          publisher.name, hex(publisher.data)))
    
    
    class BinaryFormatter:
    
        def notify(self, publisher):
            print("{}: '{}' has now bin data = {}".format(type(self).__name__,
                                                          publisher.name, bin(publisher.data)))
    
    
    def main():
        df = DefaultFormatter('test1')
        print(df)
    
        print()
        hf = HexFormatter()
        df.add(hf)
        df.data = 3
        print(df)
    
        print()
        bf = BinaryFormatter()
        df.add(bf)
        df.data = 21
        print(df)
    
        print()
        df.remove(hf)
        df.data = 40
        print(df)
    
        print()
        df.remove(hf)
        df.add(bf)
        df.data = 'hello'
        print(df)
    
        print()
        df.data = 15.8
        print(df)
    
    if __name__ == '__main__':
        main()
    observer.py

    面向对象编程

    面向对象编程着力于在对象交互时改变它们的状态,状态机是一个抽象机器,有两个关键部分,状态和转换。状态是指系统的当前(激活) 状况,转换是指从一个状态切换 到另一个状态,因某个事件或条件的触发而开始。通常,在一次转换发生之前或之后会执行一个 或一组动作.

    状态模式是一个或多个有限状态机(简称状态机)的实现,用于解决一个特定的软件工程问题

    # Author:song
    from state_machine import State, Event, acts_as_state_machine, after, before, InvalidStateTransition
    
    
    @acts_as_state_machine
    class Process:
        created = State(initial=True)
        waiting = State()
        running = State()
        terminated = State()
        blocked = State()
        swapped_out_waiting = State()
        swapped_out_blocked = State()
    
        wait = Event(from_states=(created, running, blocked,
                                  swapped_out_waiting), to_state=waiting)
        run = Event(from_states=waiting, to_state=running)
        terminate = Event(from_states=running, to_state=terminated)
        block = Event(from_states=(running, swapped_out_blocked),
                      to_state=blocked)
        swap_wait = Event(from_states=waiting, to_state=swapped_out_waiting)
        swap_block = Event(from_states=blocked, to_state=swapped_out_blocked)
    
        def __init__(self, name):
            self.name = name
    
        @after('wait')
        def wait_info(self):
            print('{} entered waiting mode'.format(self.name))
    
        @after('run')
        def run_info(self):
            print('{} is running'.format(self.name))
    
        @before('terminate')
        def terminate_info(self):
            print('{} terminated'.format(self.name))
    
        @after('block')
        def block_info(self):
            print('{} is blocked'.format(self.name))
    
        @after('swap_wait')
        def swap_wait_info(self):
            print('{} is swapped out and waiting'.format(self.name))
    
        @after('swap_block')
        def swap_block_info(self):
            print('{} is swapped out and blocked'.format(self.name))
    
    
    def transition(process, event, event_name):
        try:
            event()
        except InvalidStateTransition as err:
            print('Error: transition of {} from {} to {} failed'.format(process.name,
                                                                        process.current_state, event_name))
    
    
    def state_info(process):
        print('state of {}: {}'.format(process.name, process.current_state))
    
    
    def main():
        RUNNING = 'running'
        WAITING = 'waiting'
        BLOCKED = 'blocked'
        TERMINATED = 'terminated'
    
        p1, p2 = Process('process1'), Process('process2')
        [state_info(p) for p in (p1, p2)]
    
        print()
        transition(p1, p1.wait, WAITING)
        transition(p2, p2.terminate, TERMINATED)
        [state_info(p) for p in (p1, p2)]
    
        print()
        transition(p1, p1.run, RUNNING)
        transition(p2, p2.wait, WAITING)
        [state_info(p) for p in (p1, p2)]
    
        print()
        transition(p2, p2.run, RUNNING)
        [state_info(p) for p in (p1, p2)]
    
        print()
        [transition(p, p.block, BLOCKED) for p in (p1, p2)]
        [state_info(p) for p in (p1, p2)]
    
        print()
        [transition(p, p.terminate, TERMINATED) for p in (p1, p2)]
        [state_info(p) for p in (p1, p2)]
    
    if __name__ == '__main__':
        main()
    state.py

    策略模式
    策略模式(Strategy pattern)鼓励使用多种算法来解决一个问题,其杀手级特性是能够在运 行时透明地切换算法(客户端代码对变化无感知)。因此,如果你有两种算法,并且知道其中一 种对少量输入效果更好,另一种对大量输入效果更好,则可以使用策略模式在运行时基于输入数据决定使用哪种算法

    策略模式的另一个应用是创建不同的样式表现,为了实现可移植性(例如,不同平台之间断行的不同)或动态地改变数据的表现.

    # Author:song
    # coding: utf-8
    
    import time
    SLOW = 3  # 单位为秒
    LIMIT = 5   # 字符数
    WARNING = 'too bad, you picked the slow algorithm :('
    
    
    def pairs(seq):
        n = len(seq)
        for i in range(n):
            yield seq[i], seq[(i + 1) % n]
    
    
    def allUniqueSort(s):
        if len(s) > LIMIT:
            print(WARNING)
            time.sleep(SLOW)
        srtStr = sorted(s)
        for (c1, c2) in pairs(srtStr):
            if c1 == c2:
                return False
        return True
    
    
    def allUniqueSet(s):
        if len(s) < LIMIT:
            print(WARNING)
            time.sleep(SLOW)
        return True if len(set(s)) == len(s) else False
    
    
    def allUnique(s, strategy):
        return strategy(s)
    
    
    def main():
        while True:
            word = None
            while not word:
                word = input('Insert word (type quit to exit)> ')
                if word == 'quit':
                    print('bye')
                    return
    
                strategy_picked = None
                strategies = {'1': allUniqueSet, '2': allUniqueSort}
                while strategy_picked not in strategies.keys():
                    strategy_picked = input('Choose strategy: [1] Use a set, [2] Sort and pair> ')
    
                    try:
                        strategy = strategies[strategy_picked]
                        print('allUnique({}): {}'.format(word, allUnique(word, strategy)))
                    except KeyError as err:
                        print('Incorrect option: {}'.format(strategy_picked))
    
    if __name__ == '__main__':
        main()
    strategy.py

    模板设计模式

    模板设计模式旨在消除代码重复。如果我们发现结构相近的(多个)算法中有重复代码,则可以把算法的不变(通用)部分留在一个模板方法/函数中,把易变(不同的部分移到动作/钩子方法/函数中

    在实现结构相近的算法时,可以使用模板模式来消除冗余代码。具体实现方式是使用动作/钩子方法/函数来完成代码重复的消除.

    # Author:song
    from cowpy import cow
    
    """实现一个横幅生成器。想法很简单,将一段文本发送给一个函数,该函数要
    生成一个包含该文本的横幅。横幅有多种风格,比如点或虚线围绕文本。横幅生成器有一个默认
    风格,但应该能够使用我们自己提供的风格函数generate_banner()是我们的模板函数。它接受一个输入参数(msg,希望横幅包含
    的文本)和一个可选参数(style,希望使用的风格)。默认风格是dots_style"""
    
    
    def dots_style(msg):
        msg = msg.capitalize()
        msg = '.' * 10 + msg + '.' * 10
        return msg
    
    
    def admire_style(msg):
        msg = msg.upper()
        return '!'.join(msg)
    
    
    def cow_style(msg):
        msg = cow.milk_random_cow(msg)
        return msg
    
    
    def generate_banner(msg, style=dots_style):
        print('-- start of banner --')
        print(style(msg))
        print('-- end of banner --
    
    ')
    
    
    def main():
        """main()函数向横幅发送文本“happy coding”,并使用所有可用风格将横幅输出到标准输出"""
        msg = 'happy coding'
        [generate_banner(msg, style) for style in (dots_style, admire_style, cow_style)]
    
    if __name__ == '__main__':
        main()
    template.py

    参考文献:

    《Python设计模式》

  • 相关阅读:
    String类的常用成员方法
    String类和StringBuffer类
    记事本
    GridLayout 可使容器中的各个组件呈网格状布局
    在使用add()方法添加组件到容器时,必须指定将其放置在哪个区域中
    每个容器都有一个布局管理器
    框架一般用作Java应用程序的窗口,而Applet是Java小程序的窗口
    面板是一种透明的容器,没有标题和边框
    要生成一个窗口,通常使用Window的子类Frame类进行实例化
    分布式系统 (大规模分布式系统原理解析和架构实践)
  • 原文地址:https://www.cnblogs.com/master-song/p/9449541.html
Copyright © 2011-2022 走看看