python常用设计模式

设计模式@TOC

1.设计模式简介

设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理地运用设计模式可以完美地解决很多问题,每种模式在现实中都有相应的原理来与之对应,每种模式都描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是设计模式能被广泛应用的原因。

什么是 GOF(四人帮,全拼 Gang of Four)?

在 1994 年,由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 四人合著出版了一本名为 Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用的面向对象软件元素) 的书,该书首次提到了软件开发中设计模式的概念。

四位作者合称 GOF(四人帮,全拼 Gang of Four)。他们所提出的设计模式主要是基于以下的面向对象设计原则。

1.对接口编程而不是对实现编程。
2.优先使用对象组合而不是继承。

2.设计模式原则

OPP七大设计原则

1.单一职责原则(Single Responsiblity Principle, SRP)
一个类负责一项职责。

2.开闭原则(Open Closed Principle, OCP)
一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。

3.里氏替换原则(Liskov Substitution Principle, LSP)
继承与派生的规则(子类可替换父类)。

4.依赖倒转原则(Dependency Inversion Principle, DIP)
高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。即针对接口编程,不要针对实现编程。

5.接口隔离原则(Interface Segregation Principle, ISP)
建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少。

6.组合/聚合复用原则(Composite/Aggregate Reuse Principle, CARP)
尽量使用组合和聚合少使用继承的关系来达到复用的原则。

7.最小知识原则(迪米特法则)(Principle of Least Knowledge, PLK)
高内聚,低耦合(high cohesion low coupling)。

3.三种最基本的设计模式:

1.创建模式,提供实例化的方法,为适合的状况提供相应的对象创建方法。
Factory Method(工厂方法)
Abstract Factory(抽象工厂)
Builder(建造者)
Prototype(原型)
Singleton(单例)

2.结构化模式,通常用来处理实体之间的关系,使得这些实体能够更好地协同工作。
Adapter Class/Object(适配器)
Bridge(桥接)
Composite(组合)
Decorator(装饰)
Facade(外观)
Flyweight(享元)
Proxy(代理)

3.行为模式,用于在不同的实体建进行通信,为实体之间的通信提供更容易,更灵活的通信方法。
Interpreter(解释器)
Template Method(模板方法)
Chain of Responsibility(责任链)
Command(命令)
Iterator(迭代器)
Mediator(中介者)
Memento(备忘录)
Observer(观察者)
State(状态)
Strategy(策略)
Visitor(访问者)

1)简单工厂模式
内容:不直接向客户端暴露对象创建的实现细节,而是通过一个工厂类来负责创建产品类的实例。
优点:
隐藏了对象创建的实现细节
客户端不需要修改代码
缺点:
违反了单一职责原则,将创建逻辑集中到一个工厂类里
当添加新产品是,需要修改工厂类代码,违反了开闭原则

2)简单工厂模式
内容:定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使一个类的实例化延迟到其子类。
优点:
每个具体产品都对应一个具体工厂类,不需要修改工厂类代码
隐藏了对象创建的实现细节
缺点:
每增加一个具体产品类,就必须增加一个相应的具体工厂类

3)抽象工厂模式
内容:定义一个工厂类接口,让工厂子类来创建一系列相关或相互依赖的对象。
优点:
将客户端与类的具体实现相分离
每个工厂创建了一个完整的产品系列,使得易于交换产品系列
有利于产品的一致性(即产品之间的约束关系)
缺点:
难以支持新种类(抽象)产品

4)建造者模式
内容:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
优点:
隐藏了一个产品的内部结构和装配过程
将构造代码与表示代码分开
可以对构造过程进行更精细的控制

5)单例模式
内容:保证一个类只有一个实例,并提供一个访问它的全局访问点。
优点:
对唯一实例的受控访问
单例相当于全局变量,但防止了命名空间被污染
缺点:
难以支持新种类(抽象)产品

class Singleton(object):
    """docstring for Singleton"""
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            cls._instance = super(Singleton, cls).__new__(cls)
        return cls._instance 

class MyClass(Singleton):
    """docstring for MyClass"""
    def __init__(self, x):
        self.x = x

a = MyClass(10)
b = MyClass(20)

print(a.x)
print(b.x)
print(id(a), id(b))

------------------------------------------------

6)适配器模式
内容:将一个类的接口转换成客户希望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
两种实现方式:
类适配器:使用多继承
对象适配器:使用组合

7)桥模式
内容:将一个事物的两个维度分离,使其都可以独立地变化

8)组合模式
内容:将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
适用场景:
表示对象的部分-整体层次结构。
希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
优点:
定义了包含基本对象和组合对象的类层次结构
简化客户端代码,即客户端可以一致地使用组合对象和单个对象
更容易增加新类型的组件

from abc import ABCMeta, abstractmethod

# 抽象组件
class Graphic(metaclass=ABCMeta):
    @abstractmethod
    def draw(self):
        pass

# 叶子组件
class Point(Graphic):
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return "点(%s, %s)" % (self.x, self.y)

    def draw(self):
        print(str(self))

# 叶子组件
class Line(Graphic):
    def __init__(self, p1, p2):
        self.p1 = p1
        self.p2 = p2

    def __str__(self):
        return "线段(%s, %s)" % (self.p1, self.p2)

    def draw(self):
        print(str(self))

# 复合组件
class Picture(Graphic):
    def __init__(self, iterable):
        self.children = []
        for g in iterable:
            self.add(g)

    def add(self, graphic):
        self.children.append(graphic)

    def draw(self):
        print("---复合图形---")
        for g in self.children:
            g.draw()
        print("---复合图形---")
        
p1 = Point(2, 3)
l1 = Line(Point(3,4), Point(6,7))
l2 = Line(Point(1,5), Point(2,8))
pic1 = Picture([p1, l1, l2])
pic1.draw()

9)外观模式
内容: 为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
优点:
减少系统相互依赖
提高了灵活性
提高了安全性

10)代理模式
内容: 为其他对象提供一种代理以控制对这个对象的访问
适用场景:
优点:
远程代理—可以隐藏对象位于远程地址空间的事实
虚代理—可以进行优化,例如根据要求创建对象
保护代理—允许访问一个对象时有一些附加的内务处理

------------------------------------------------

11)责任链模式
内容: 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
适用场景:
有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。
在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
优点:
降低耦合性:一个对象无需知道是其他哪一个对象处理其请求

class Handler:
    def successor(self, successor):
        self.successor = successor
 
class ConcreteHandler1(Handler):
    def handle(self, request):
        if request > 0 and request <= 10:
            print("in handler1")
        else:
            self.successor.handle(request)
 
class ConcreteHandler2(Handler):
    def handle(self, request):
        if request > 10 and request <= 20:
            print("in handler2")
        else:
            self.successor.handle(request)
 
class ConcreteHandler3(Handler):
    def handle(self, request):
        if request > 20 and request <= 30:
            print("in handler3")
        else:
            print('end of chain, no handler for {}'.format(request))
 
class Client:
    def __init__(self):
        h1 = ConcreteHandler1()
        h2 = ConcreteHandler2()
        h3 = ConcreteHandler3()
 
        h1.successor(h2)
        h2.successor(h3)
 
        requests = [2, 5, 14, 22, 18, 3, 35, 27, 20]
        for request in requests:
            h1.handle(request)
 
if __name__ == "__main__":
    client = Client()

12)观察者模式(发布-订阅模式)
内容:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。
适用场景:
当一个抽象模型有两个方面, 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
当对一个对象的改变需要同时改变其它对象, 而不知道具体有多少对象有待改变。
当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之, 你不希望这些对象是紧密耦合的。
优点:
目标与观察者之间的抽象耦合最小
支持广播通信

13)策略模式
内容:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。
优点:
定义了一系列可重用的算法和行为
消除了一些条件语句
可以提供相同行为的不同实现
缺点:
客户必须了解不同的策略

14)模板方法模式
内容:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤
适用场景:
一次性实现一个算法不变的部分
各个子类中的公共行为应该被提取出来并集中到一个公共父类以避免代码重复
控制子类扩展
缺点:
客户必须了解不同的策略

from abc import ABCMeta, abstractmethod
from time import sleep

# 抽象订阅者
class Window(metaclass=ABCMeta):
    @abstractmethod
    def start(self):
        pass

    @abstractmethod
    def repaint(self):
        pass

    @abstractmethod
    def stop(self):
        pass

    # 模板方法
    def run(self):
        self.start()
        while True:
            try:
                self.repaint()
                sleep(1)
            except KeyboardInterrupt:
                break
        self.stop()
            
class MyWindow(Window):
    def __init__(self, msg):
        self.msg = msg

    def start(self):
        print("the Window is running")

    def stop(self):
        print("the Window is over")

    def repaint(self):
        print(self.msg)

MyWindow("hello。。。").run()

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值