设计模式自学笔记

初学者其实不推荐一开始就是学习设计模式,建议至少等基本语法和开发框架都比较熟悉后再来学习这部分知识,并学以致用,强化理解和记忆。

23种经验设计模式索引对照表

创建型模式用来处理对象的创建过程,主要包含以下5种设计模式:
工厂方法模式(Factory Method Pattern)
抽象工厂模式(Abstract Factory Pattern)
建造者模式(Builder Pattern)
原型模式(Prototype Pattern)
单例模式(Singleton Pattern)

结构型模式用来处理类或者对象的组合,主要包含以下7种设计模式:
适配器模式(Adapter Pattern)
桥接模式(Bridge Pattern)
组合模式(Composite Pattern)
装饰者模式(Decorator Pattern)
外观模式(Facade Pattern)
享元模式(Flyweight Pattern)
代理模式(Proxy Pattern)

行为型模式用来对类或对象怎样交互和怎样分配职责进行描述,主要包含以下11种设计模式:
责任链模式(Chain of Responsibility Pattern)
命令模式(Command Pattern)
解释器模式(Interpreter Pattern)
迭代器模式(Iterator Pattern)
中介者模式(Mediator Pattern)
备忘录模式(Memento Pattern)
观察者模式(Observer Pattern)
状态模式(State Pattern)
策略模式(Strategy Pattern)
模板方法模式(Template Method Pattern)
访问者模式(Visitor Pattern)

其中比较常用的设计模式

简单工厂模式(Simple Factory Pattern) 建造者模式(Builder Pattern) 策略(Strategy)模式 工厂方法模式(Factory Method Pattern) 抽象工厂模式(Abstract Factory) 命令模式(Command Pattern) 模版方法(Template Method) 单件模式(Single Pattern) 原型模式(Prototype Pattern)

阅读学习推荐

  • 大话设计模式 -- 07年程杰版,入门经典读物,用C#讲解

  • HeadFirst设计模式 -- 入门推荐读物,讲解用的Java

  • 人人都懂设计模式:从生活中领悟设计模式(Python实现) -- 基于Python语言,例子也挺生动

  • Java设计模式:23种设计模式全面解析(超级详细) -- 小伙伴推荐的,点击直达

  • 设计模式:可复用面向对象软件的基础 -- GoF的经典著作,但不推荐新人直接阅读

观察者模式(监听模式)

定义

对象间定义一种一对多的依赖关系,当这个对象状态发生改变时,所有依赖它(观察它或监听它)的对象都会被通知并自动更新。

观察者模式是对象的行为模式,又叫 发布/订阅(Publish/Subscribe)模式模型/视图(Model/View)模式源/监听器(Source/Listener)模式从属者(Dependents)模式

观察者模式的核心:在被观察者和观察者之间建立一种自动触发的关系。

设计要点

1.设计要点

(1) 明确谁是观察者谁是被观察者。 (一般一个被观察者有多个观察者) (2) 被观察者在发送广播通知时, 无须指定具体的观察者, 观察者可以自己决定是否订阅Subject的通知 (3) 被观察者至少要有3个方法:添加观察者(监听者)、移除观察者(监听者)、通知观察者(监听者)。 (4) 添加观察者(监听者)和移除观察者(监听者)在不同的模型称谓中可能会有不同命名。注意不要被名称迷惑了。

2.推模型和拉模型

根据监听模式侧重的功能划分。

  • (1)推模型

被观察对象向观察者推送主题的详细信息不管观察者是否需要,推送的信息通常是主题对象的全部或部分数据。

  • (2)拉模型

被观察者在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到被观察者对象中获取,相当于 观察者从被观察对象中拉数据。

应用场景

[1] 对一个对象状态或者数据的更新需要其它对象同步更新,或者一个对象的更新需要依赖另一个对象的更新。

[2] 对象仅需要将自己的更新通知给其它对象,而不需要知道其它对象的细节。如:消息推送。

业务举例:手机中各种App的消息推送,Server是被观察者,各个手机App Client是观察者。

状态模式

定义

允许一个对象在其内部状态发生改变时改变其行为,使这个对象看上去就像改变了它的类型一样。

状态模式又称为对象的行为模式

状态模式的核心:一个事物(对象)有多种状态,在不同的状态下所表现出来的行为和属性不一样。

设计要点

1.设计要点 (1)在实现时,实现的场景状态有时候会非常复杂,决定状态变化的因素也非常多,故可把决定状态变化的属性单独抽象成一个类StateInfo,这样当判断状态属性是否符合当前的状态时就可以传入更多的信息。 (2)每一种状态应当只有唯一的实例。

2.状态模式的优缺点

优点:

[1] 封装了状态的转换规则, 在状态模式中可以将状态的转换代码封装在环境类中, 对状态转换代码进行集中管理,而不是分散在单个业务逻辑中。
[2] 将所有与某个状态有关的行为放到一个类中(成为状态类),使开发人员只专注于该状态下的逻辑开发。
[3] 允许状态转换逻辑与状态对象合为一体,使用时只需要注入一个不同的状态对象,即可使环境对象拥有不同的行为。
缺点:

[1] 会增加系统类和对象的个数。
[2] 状态模式的结构和实现都较为复杂,若使用不当,易导致程序结构和代码的混乱。

应用场景

[1] 一个对象的行为取决于它的状态,并且它在运行时可能经常改变它的状态,从而改变它的行为。

[2] 一个操作中含有庞大的多分支的条件语句,这些分支依赖于该对象的状态,且每一个分支的业务逻辑都非常复杂时,则可以使用状态模式来拆分不同的分支逻辑,使程序有更好的可读性和可维护性。

中介模式(调停模式)

定义

用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,且可以独立地改变它们之间的交互。

设计要点

1.设计要点

设计时要找到并区分这3个角色:

(1) 交互对象(InteractiveObject): 要进行交互的一系列对象。 (2) 中介者(Mediator): 负责协调各个对象之间的交互。 (3) 具体中介者(Mediator):中介的具体实现。

2.中介模式的优缺点

优点:
[1] 中介者(Mediator)将原本分布于多个对象间的行为集中在一起,作为一个独立的概念并将其封装在一个对象中,简化了对象之间的交互。
[2] 将多个调用者与多个实现者之间多对多的交互关系,转换为一对多的交互关系,一对多的交互关系更易于理解、维护和扩展,大幅度减少了多个对象之间相互交叉引用的情况。
缺点:
[1] 中介者(Mediator)承接了所有的交互逻辑,交互的复杂度转变成了中介者的复杂度,中介者类会变得越来越庞大和复杂,直至难以维护。
[2] 中介者出问题会导致多个使用者同时出问题。

应用场景

[1] 一组对象以定义良好但复杂的方式进行通信,但产生的相互依赖关系结构混乱且难以理解。

[2] 一个对象引用其它很多对象,并且直接与这些对象通信,导致难以复用该对象。

[3] 想通过一个中间类来封装多个类中的行为,同时又不想生成太多的子类。

装饰模式

定义

动态地给一个对象增加一些额外的职责。就拓展对象来说,装饰模式 比 成为子类的方式 更为灵活。

Python中的装饰器,请见Python相关章节笔记。

设计要点

1.设计要点

2.装饰模式的优缺点

优点:
[1] 使用装饰模式来实现扩展比使用继承更加灵活,它可以在不创造更多子类的情况下,将对象的功能加以扩展。
[2] 可以动态的给一个对象附加更多的功能。
[3] 可以用不同的装饰器进行多重装饰,装饰的顺序不同,可能产生不同的效果。
[4] 装饰类和被装饰类可以独立发展,不会相互耦合 (装饰模式相当于继承的一个替代模式)。
缺点:
[1] 与继承相比,用装饰的方式拓展功能容易出错,排错也更困难。对于多次装饰的对象,调试寻找错误时可能需要逐级排查,较为烦琐。

Python装饰器 与 装饰模式 的区别

区别点 Python装饰器 装饰模式
设计思想 函数式编程思想,面向过程的思想 面向对象的编程思想
装饰的对象 可以装饰一个函数,也可以装饰一个类 装饰的是某个类中的指定方法
影响的范围 装饰一个函数时,对这个函数的所有调用都起效;装饰一个类时,对这个类的所有实例都起效 只对装饰的这一个对象起效

应用场景

[1] 有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长时。

[2] 需要动态地增加或撤销功能时。

[3] 不能采用生成子类的方法进行扩充时,类的定义不能用于生成子类(如:Java中的Final类)

单例模式

定义

确保一个类只有一个实例,并且提供一个访问它的全局方法。

单例模式的实现方式

python 4种 (带补充)

应用场景

[1] 希望这个类只有一个且只能有一个实例。

[2] 项目中的一些全局管理类(Manager)可以用单例模式来实现。

原型模式(克隆模式)

定义

应用场景