Python 常见设计模式

Python 常见设计模式

创建型模式

单例模式

单例模式(Singleton Pattern)是一种常见的软件设计模式,该模式主要目的是确保某一类只有一个实例存在。当你希望整个系统中,某个类只出现一次实例时,单例对象就能派上用场。

比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个AppConfig的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建AppConfig对象的实例,这就导致系统中存在多个AppConfig的实例对象,而这样会严重浪费内存资源,尤其是配置文件内容很多的情况下。事实上,类似AppConfig这样的类,我们希望在程序运行期间只存在一个实例对象。

# -*- coding: utf-8 -*-
# @File   : singleton_pattern.py
# @Author : Runpeng Zhang
# @Date   : 2020/2/12
# @Desc   : 演示单例模式(Singleton Pattern)

class Singleton(object):
    def __init__(self):
        pass

    def __new__(cls, *args, **kwargs):
        if not hasattr(Singleton, "_instance"):  # 反射
            Singleton._instance = object.__new__(cls)
        return Singleton._instance


obj1 = Singleton()
obj2 = Singleton()
print(obj1, obj2)
"""
<__main__.Singleton object at 0x00000208FD43B2E8> 
<__main__.Singleton object at 0x00000208FD43B2E8>
"""

工厂模式

工厂模式就是一个软件开发中用来创建对象的设计模式。

工厂模式包涵一个超类。这个超类提供一个抽象化的接口来创建一个特定类型的对象,而不是决定哪个对象可以被创建。

为了实现此方法,需要创建一个工厂类创建并返回。

当程序运行输入一个“类型”的时候,需要创建此相应的对象。这就用到了工厂模式。在如此情形中,实现代码基于工厂模式,可以达到可扩展,可维护的代码。当增加一个新的类型,不再需要修改已存在的类,只增加能够产生新类型的子类。

简短的说,当以下情形可以使用工厂模式:

  • 不知道用户想要创建什么样的对象
  • 当你想要创建一个可扩展的关联在创建类与支持创建对象的类之间。

一个例子更能很好的理解以上的内容:
1、我们有一个基类Person,包含获取名字、性别的方法。有两个子类Male和Female,我们可以打招呼。还有一个工厂类。
2、工厂类有一个方法名getPerson有两个输入参数,名字和性别。
3、用户使用工厂类,通过调用getPerson方法。

在程序运行期间,用户传递性别给工厂,工厂创建一个与性别有关的对象。因此工厂类在运行期,决定了哪个对象应该被创建。

# -*- coding: utf-8 -*-
# @File   : factory_pattern.py
# @Author : Runpeng Zhang
# @Date   : 2020/2/12
# @Desc   : 演示工厂模式(Factory Pattern)


class Person:
    def __init__(self):
        self.name = None
        self.gender = None

    def getName(self):
        return self.name

    def getGender(self):
        return self.gender


class Male(Person):
    def __init__(self, name):
        print("Hello Mr." + name)


class Female(Person):
    def __init__(self, name):
        print("Hello Miss." + name)


class Factory:
    def getPerson(self, name, gender):
        if gender == "M":
            return Male(name)
        elif gender == "F":
            return Female(name)


if __name__ == '__main__':
    factory = Factory()
    person = factory.getPerson("Rp", "M")

建造者模式

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

相同模式:思路和模板方法模式都像,模板方法是封存算法流程,对某些细节,提供接口由子类修改,建造者模式更为高层一点,将所有细节都交给子类实现。

一个例子更能很好的理解以上的内容:

  • 有一个接口类,定义创建对象的方法。一个指挥员类,接受创造者对象为参数。两个创造者类,创建对象方法相同,内部创建可自定义。
  • 有一个指挥员,两个创造者(胖子、瘦子),指挥员可以指定由哪个创造者来创造。
# -*- coding: utf-8 -*-
# @File   : builder_pattern.py
# @Author : Runpeng Zhang
# @Date   : 2020/2/12
# @Desc   : 演示建造者模式(Factory Pattern)


from abc import ABCMeta, abstractmethod


class Builder:
    __metaclass__ = ABCMeta

    @abstractmethod
    def draw_left_arm(self):
        pass

    @abstractmethod
    def draw_right_arm(self):
        pass

    @abstractmethod
    def draw_left_foot(self):
        pass

    @abstractmethod
    def draw_right_foot(self):
        pass

    @abstractmethod
    def draw_head(self):
        pass

    @abstractmethod
    def draw_body(self):
        pass


class Thin(Builder):
    def draw_left_arm(self):
        print('画左手')

    def draw_right_arm(self):
        print('画右手')

    def draw_left_foot(self):
        print('画左脚')

    def draw_right_foot(self):
        print('画右脚')

    def draw_head(self):
        print('画头')

    def draw_body(self):
        print('画苗条的身体')


class Fat(Builder):
    def draw_left_arm(self):
        print('画左手')

    def draw_right_arm(self):
        print('画右手')

    def draw_left_foot(self):
        print('画左脚')

    def draw_right_foot(self):
        print('画右脚')

    def draw_head(self):
        print('画头')

    def draw_body(self):
        print('画壮硕的身体')


class Director():
    def __init__(self, person):
        self.person = person

    def draw(self):
        self.person.draw_left_arm()
        self.person.draw_right_arm()
        self.person.draw_left_foot()
        self.person.draw_right_foot()
        self.person.draw_head()
        self.person.draw_body()


if __name__ == '__main__':
    thin = Thin()
    fat = Fat()
    director_thin = Director(thin)
    director_thin.draw()
    print('-----')
    director_fat = Director(fat)
    director_fat.draw()

结构性模式

适配器模式

所谓适配器是指一种接口适配技术,它可以通过某个类来使用另一个接口与之不兼容的类,运行此模式,两个类的接口都无须改动。

适配器模式主要应用于希望复用一些现存的类,但是接口有与复用环境要求不一致的情况,比如在需要对早期代码复用一些功能等应用上很有实际价值。

应用场景:系统数据和行为都很正确,但接口不符合时,目的是使控制范围之外的一个原有对象与某个接口匹配,适配器模式主要应用于希望复用一些现存的类,但接口又与复用环境不一致的情况。

在这里插入图片描述

# -*- coding: utf-8 -*-
# @File   : target_pattern.py
# @Author : Runpeng Zhang
# @Date   : 2020/2/12
# @Desc   : 演示适配器模式(Adapter Pattern)


class Target(object):
    def request(self):
        print('普通请求')


class Adaptee(object):
    def specific_request(self):
        print('特殊请求')


class Adapater(object):
    def __init__(self):
        self.adaptee = Adaptee()

    def request(self):
        self.adaptee.specific_request()


if __name__ == '__main__':
    target = Adapater()
    target.request()

外观模式

外观模式又叫做门面模式。在面向对象程序设计中,解耦是一种推崇的理念。但事实上由于某些系统过于复杂,从而增加了客户端与子系统之间的耦合度。

例如:在家观看多媒体影院时,更希望按下一个按钮就能实现影碟机,电视,音响的协同工作,而不是说每个机器都要操作一遍。这种情况下可以采用外观模式,即引入一个类对子系统进行包装,让客户端与其进行交互。

外观模式(Facade Pattern):外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。外观模式又称为门面模式,踏实一种对象结构型模式。

# -*- coding: utf-8 -*-
# @File   : facade_pattern.py
# @Author : Runpeng Zhang
# @Date   : 2020/2/12
# @Desc   : 演示外观模式(Facade Pattern)


from enum import Enum
from abc import ABCMeta, abstractmethod

State = Enum('State', 'new running slepping 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 '{}'".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)


if __name__ == '__main__':
    os = OperatingSystem()
    os.start()
    os.create_file('foo', 'hello', '-rw-r-r')
    os.create_process('bar', 'ls/tmp')


"""
booting the FileServer
booting the ProcessServer
trying to create the file 'hello' for user 'foo'with permissions -rw-r-r
trying to create the process 'ls/tmp'
"""

享元模式

运用共享技术有效地支持大量细粒度的对象。
内部状态:享元对象中不会随环境改变而改变的共享部分。比如围棋棋子的颜色。
外部状态:随环境改变而改变、不可以共享的状态就是外部状态。比如围棋棋盘的位置。

很多场景:程序中使用了大量的对象,如果删除对象的外部状态,可以用相对较少的共享对象取代很多组对象,就可以考虑使用享元模式。

# -*- coding: utf-8 -*-
# @File   : xiangyuan_pattern.py
# @Author : Runpeng Zhang
# @Date   : 2020/2/12
# @Desc   : 演示享元模式


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()

"""
render a tree of type TreeType.apple_tree and age 28 at (29, 80)
render a tree of type TreeType.apple_tree and age 28 at (38, 94)
render a tree of type TreeType.apple_tree and age 16 at (82, 84)
render a tree of type TreeType.apple_tree and age 18 at (43, 98)
render a tree of type TreeType.apple_tree and age 2 at (84, 72)
render a tree of type TreeType.apple_tree and age 16 at (89, 29)
render a tree of type TreeType.apple_tree and age 30 at (91, 53)
render a tree of type TreeType.apple_tree and age 12 at (92, 73)
render a tree of type TreeType.apple_tree and age 3 at (11, 54)
render a tree of type TreeType.apple_tree and age 1 at (34, 59)
render a tree of type TreeType.cherry_tree and age 11 at (67, 72)
render a tree of type TreeType.cherry_tree and age 27 at (65, 81)
render a tree of type TreeType.cherry_tree and age 27 at (10, 48)
render a tree of type TreeType.peach_tree and age 11 at (35, 38)
render a tree of type TreeType.peach_tree and age 3 at (58, 83)
render a tree of type TreeType.peach_tree and age 18 at (73, 50)
render a tree of type TreeType.peach_tree and age 24 at (94, 3)
render a tree of type TreeType.peach_tree and age 4 at (2, 9)
trees rendered: 18
trees actually created: 3
4866032 == 4866032? True
4866032 == 4742704? False

"""

模式-视图-控制器模式

代理模式

行为型模式

责任链模式

命令模式

解释器模式

观察者模式

状态模式

策略模式

模板模式

Rp_
发布了103 篇原创文章 · 获赞 28 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_41738030/article/details/104277578
今日推荐