设计模式之行为模式
一、行为模式概述
行为模式涉及到算法和对象职责的分配。行为模式不仅描述对象或类的模式,还描述了它们之间的通信模式。
行为类模式:使用继承机制在类间实现分派行为。(模板方法模式,迭代器模式)
行为对象模式:使用对象复合而不是继承。一些行为对象模式描述了一组对等的对象怎样相互协作已完成其中任一个对象都无法单独完成的任务。
二、行为模式内容
1、职责链模式(责任链模式)
(1)功能
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连城一条链,并沿着这条链传递请求,直到有一个对象处理它为止。
(2)适用性
1、有多个对象(处理者)可以处理一个请求时,具体哪个处理对象先处理运行时候自动确定
(3)结构
(4)参与者
Handler: 处理请求的公共接口,包含有下一个处理者引用
ConcreteHandler:处理请求的具体处理者
(5)优缺点
1)优点:降低请求发送者与请求处理者之间的耦合。增强了给对象指派职责的灵活性
(6)相关模式
1)组合模式:职责链模式经常与组合模式一起使用,这种情况下,一个构件的后继就是它的父构件
2、命令模式
背景分析:通常命令请求的发起者和实现者都是同一个对象,就使得命令的发起者和命令的实现者(执行者)紧紧的耦合在一起。这种情况下,增加新的命令就需要修改原来的代码这就不符合开放封闭原则(一个软件实体应该对扩展开放,对修改关闭,即软件实体应该尽量在不修改原有的代码下进行扩展),所以需要一种模式将命令的发起者和命令的执行者(实现者)分离开来,实现两者的解耦。
会经常变化变动的地方:命令,更多类型更多的命令会新增。应该做到开放命令的扩展。
不变的地方:命令的调用方(也就是命令的发起者)。应该做到禁止修改
(1)功能
将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行储存、传递、调用、增加与管理。
(2)适用性
1)在不同的时刻指定、排列和执行请求
2)支持取消、撤销操作
(3)结构
(4)参与者
Command :声明执行操作的接口,提供给命令发起者(请求者)的对外统一接口。
ConcreteCommand:实现Command接口的,调用命令接收者Receiver执行具体操作的
Receiver:命令操作的执行者,每个命令抽象接口的实现者(具体命令)都持有一个命令的接收者,也就是命令最终的执行者。最终执行命令,完成命令操作的对象。
Invoker:处理命令请求的。发起命令的主体,发起者。
Client: 1)创建Receiver命令的接收者,也是最终执行具体命令的对象。
2)用Receiver建立具体命令ConcreteCommand并赋值给Commond抽象。
3)用Common对象(指向某个具体实例)创建命令请求者也就是命令的发起者Invoker
4)发起者Invoker发起命令请求(调用common对象的excutor()方法)
5)具体命令ConcreteCommand接收到发起者发起的命令,调用命令接收者Receiver,执行命令
6)命令接收者Receiver执行命令
(5)优缺点
1)优点:a.将调用操作的对象与知道如何实现该操作的对象解耦;
b.增加新的Command很容易,不用修改已有的类
(6)相关模式
1)组合模式:
2)备忘录模式:
3、解释器模式
(1)功能
给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
(2)适用性
适用于简单的文法,对于复杂文法,文法的类层次结构变得庞大而无法管理
(3)结构
(4)参与者
Context: 解释器的上下文内容,即除解释器外的全局信息,包含了输入待解释信息
AbastractExpression: 文法表示的抽象接口,也是解释操作的抽象接口。所有解释操作的父接口
TerminalExpression:终结符表达式,文法中终结符的解释器。终结符表达式,实现与文法中终结符相关联的解释操作
NonterminalExpression:非终结符表达式,为文法中非终结符实现解释操作。文法中每一条规则对应一个解释器(也就是非终结符表达式)
Client:客户端
(5)优缺点
(6)相关模式
1)组合模式:抽象语法树是一个复合模式的示例
2)享元模式:说明了如何在抽象语法树中共享终结符
3)访问者模式:用来维护抽象语法树中各个节点的行为
4)迭代器模式:可以迭代遍历解释器
4、迭代器模式
(1)功能
提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示
(2)适用性
1)聚合对象,不需要暴露内部结构
(3)结构
(4)参与者
(5)优缺点
(6)相关模式
5、中介者模式
(1)功能
用一个中介对象来封装一系列的对象交互。中介者使得各对象不需要显示的相互引用,从而使其耦合松散,而且可以独立的改变他们之间的交互。
(2)适用性
1)一组对象需要进行相关复杂的交互通信操作,想要实现对象之间交互通信操作的解耦
2)想要对象一组对象交互通信操作进行集中控制
(3)结构
(4)参与者
(5)优缺点
(6)相关模式
1)外观模式:外观模式是对一个对象的子系统进行抽象,是单向的即Facade对象将请求转发给子系统
而中介模式多向的,
2)观察者模式:Colleage可以使用观察者模式与Mediator通信
6、备忘录模式
(1)功能
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后可以将该对象恢复到原先保存的状态。
(2)适用性
1)需要维护对象属性历史的
2)需要实现撤销操作,恢复原先的状态的
(3)结构
(4)参与者
Originator:需要保存内部状态的对象,也是发起创建一个备忘录的对象
Memento:备忘录,保存了Originator对象内部状态的对象
Caretaker:管理备忘录Memento的对象
(5)优缺点
(6)相关模式
1)迭代模式:备忘录模式可用于迭代
2)命令模式:命令可以使用备忘录来为可撤销的操作维护状态
7、观察者模式
(1)功能
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。
(2)适用性
1)存在依赖关系的两方面。当依赖的一方做出更改的时候,另一方也要自动做出调整。
(3)结构
(4)参与者
Observer:抽象观察者接口,
ConcreteObserver: 实现Observer接口的具体观察者实现类
Subject: 抽象主题接口,保存了订阅该主题的观察者的引用(观察者列表)还提供了观察者订阅该主题和取消订阅,接收更新通知的接口。
ConcreteSubject:实现Subject接口的具体主题实现类。
(5)优缺点
1)优点:实现目标和观察者的抽象耦合
2)缺点:依赖于抽象观察者和更新操作。对应哪些不能实现抽象观察者接口的类,就不能实现接收通知。还有对于那些没有更新操作,但是有其他操作的无法接收到通知操作。
解决:使用委托,主题依赖于委托,而不是抽象观察者接口。
(6)相关模式
1)中介者模式:
2)单例模式:
8、状态模式
状态模式是针对一个对象体系(不存在对象结构体系即父类子类关系)时候,对象的状态和对象的行为之间存在依赖控制关系,不同的状态对应对象不同的状态。状态变化的时候紧跟着行为的变化。
状态模式聚焦于对象内部的状态和行为方式直接的依赖控制关系。
(1)功能
当一个对象的内部状态改变时,允许改变其行为,这个对象看起来像是改变了其类。
对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。
(2)适用性
1)主要解决的是当控制一个对象状态转换的条件表达式过于复杂的时的情况。把状态的判断逻辑移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。
2)当对象的行为取决于状态,并且它必须在运行时刻根据状态变化改变它的行为时
(3)结构
(4)参与者
Context: 根据State状态变化而具有不同行为的对象的抽象接口。内部维护了一个用State表示的内部状态
State: Context内部状态抽离出来的抽象类.
ConcreteState:表示具体的状态类,实现State接口。实现了Context特定状态下执行特定的行为操作。
(5)优缺点
1)优点:
将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。从而消除了判断的条件分支语句。
(6)相关模式
1)单例模式:状态通常都是单例的
2)享元模式:解释了何时以及怎样共享状态对象。
9、策略模式
策略模式是针对众多的同一类对象的相同行为方式存在不同的具体行为方式的时候,将对象的行为方式抽象出来,通过组合方式将具体的行为方式拖延到子类中决定。
策略模式侧重于一个对象体系内(具有相同抽象行为特征的父子类关系),对象之间的不同行为上的差异
(1)功能
定义一系列算法,把它们一个个都封装起来,并且使它们可以相互替换。
一个对象(类)由状态(类的不同字段)和行为动作(类的不同方法)组成。如果对象的同一个行为动作存在不同(存在变化)则将变换抽象出来,并定义一系列的算法。通过组合方式将对象和对象的抽象行为动作进行组合,然后具体的行为动作方式交由对象的子类具体实现。
(2)适用性
1)需要使用一个算法的不同变体
2)一个类定义了多种行为,并且这些行为在类中以多个条件语句出现时
3)许多相关类只是行为有异,需要在运行时设置它的行为
(3)结构
(4)参与者
Strategy:抽象策略接口
ConcreteStrategy:具体策略类,实现了Strategy接口
Context:上下文,保存了一个Strategy的引用
(5)优缺点
1)优点:算法的变化不会影响到使用该算法的客户端
(6)相关模式
1)享元模式:策略Strategy对象通常是很好的轻量级对象
2)状态模式:状态模式是将对象不同的状态抽离出来。策略模式是将算法策略行为抽离出来
10、模板方法模式
(1)功能
定义一个操作中的算法骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
(2)适用性
1)一次性实现一个算法的不变部分,并将可变的行为留给子类来实现。
(3)结构
(4)参与者
(5)优缺点
1)优点:提供了很好的代码复用平台
(6)相关模式
1)工厂方法模式: 常被模版方法调用
2)策略模式:模板方法使用继承来改变算法的一部分,策略模式使用委托来改变整个算法。
11、访问者模式
(1)功能
描述的是一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
访问者模式把数据结构和作用于数据结构之上的操作之间的耦合度解脱开,使得操作集合可以相对的自由地演化。
目的是要把处理从数据结构中分离出来
(2)适用性
1)访问者模式适用于数据结构相对稳定的系统
2)需要分离数据结构与处理时
(3)结构
(4)参与者
Visitor: 操作部分的抽象接口,声明每个数据的访问操作Visitor
ConcreteVisitor:实现Visitor接口,具体实现类,实现每个数据的访问操作Visitor
Element:数据结构部分的抽象接口,声明Accept操作(利用双分派技术,实现处理与数据结构的分离)
ConcreteElement: 实现Element接口,数据结构具体实现类,实现Accept操作
ObjectStruct:维护一个Element列表的接口
(5)优缺点
1)优点:增加新的操作很容易
2)缺点:增加新的数据结构很困难
(6)相关模式
三、总结对比
行为模式 |
特性 |
参与者 |
适用范围 |
优缺点 |
职责链模式 |
分离了请求的发送者与请求的处理者 | 一个处理请求的类层次结构 (每个请求类都维护者下一个请求类对象的引用) |
有多个对象(处理者)可以处理一个请求时,具体哪个处理对象先处理运行时候自动确定 | |
命令模式 |
将调用操作的对象与知道如何实现该操作的对象解耦; 将请求封装在对象里面,就可以传递该对象或者以其他方式使用 |
一个命令层次结构 (命令抽象接口维护一个执行操作的接收者,也就是执行命令的) 一个执行操作的接收者 (执行命令的最终者) 一个接收命令请求的 (维护一个命令对象列表) |
1)在不同的时刻指定、排列和执行请求 2)支持取消、撤销操作 |
|
解释器模式 |
根据输入文本得出经过处理后的文本信息 | 一个解释器上下文 一个解释器抽象接口 一个终结符解释器 一个非终结符解释器 |
适用于简单的文法,对于复杂文法,文法的类层次结构变得庞大而无法管理 | |
迭代器模式 |
迭代一个聚合对象的内部对象 | 一个迭代器 一个聚合对象 |
||
中介者模式 |
集中管理对象之间的交互操作 同事的消息发送和消息接收都委托中介者实现,中介者实现了同事消息的发送和同事消息的接收。 每个同事类都维护了一个中介者,每个中介者都维护了通信两端的对象。 |
一个同事层次结构 (同事抽象类维持一个中介者,同事的消息发送和消息接收都委托中介者实现) 一个中介者类层次结构 (具体中介者维护者两个通信的同事) |
需要进行交互通信操作的一系列对象 1)一组对象需要进行相关复杂的交互通信操作,想要实现对象之间交互通信操作的解耦 2)想要对象一组对象交互通信操作进行集中控制 |
|
备忘录模式 |
保存原始对象的历史状态 | 一个原始类 (发起添加备忘录信息) 一个备忘录类 (负责实现备忘信息的具体新增细节) 一个备忘录管理类 |
||
观察者模式 |
解除依赖对象之间的耦合,让耦合双方都依赖与抽象而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化。 将依赖于具体改为依赖于抽象,降低耦合度。 保存对象之间的依赖 |
一个抽象观察者接口 (声明一个接收主题更新通知的接口) 一个具体观察者实现类 一个主题抽象接口 (声明观察者添加订阅,取消订阅,通知的接口) 一个具体主题实现类 (维护一个观察者列表) |
存在依赖关系的两方面。当依赖的一方做出更改的时候,另一方也要自动做出调整 | |
状态模式 |
运行时设置状态。 将变化的状态抽离出来,使得状态变化的时候该对象可以改变它的行为 |
一个上下文 (维护一个状态对象) 一个对象类的层次结构 |
1)主要解决的是当控制一个对象状态转换的条件表达式过于复杂的时的情况。把状态的判断逻辑移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。 2)当对象的行为取决于状态,并且它必须在运行时刻根据状态变化改变它的行为时 |
|
策略模式 |
将根据条件变化的算法,从原先的条件判断语句里面抽离出来。 一个算法代表一个具体的算法策略类。 运行时改变类的行为 将算法封装在对象中,方便指定和改变对象的算法。 |
一个上下文 (维护一个算法策略抽象接口) 一个算法策略类层次结构 |
1)需要使用一个算法的不同变体 2)一个类定义了多种行为,并且这些行为在类中以多个条件语句出现时 3)许多相关类只是行为有异,需要在运行时设置它的行为 |
|
模板方法模式 |
使用继承来改变算法的一部分 实现代码的复用 将算法中,变化的部分抽离出放到子类里面实现,不变的留在父类抽象接口内。 |
一个模板方法抽象类 (一个主方法,多个由子类实现的抽象方法,主方法内调用多个子类具体实现的方法) 一个模板方法具体实现类 (子类具体实现相关抽象方法) |
一次性实现一个算法的不变部分,并将可变的行为留给子类来实现。 | |
访问者模式 |
访问者模式把数据结构和作用于数据结构之上的操作之间的耦合度解脱开,使得操作集合可以相对的自由地演化。 封装了分布于多各类之间的行为。 |
一个访问操作类的层次结构 (声明每个数据元素的访问操作接口) 一个数据元素类的层次结构 (双分派技术实现处理与数据结构分离) 一个维护元素列表的对象结构接口 |
1)访问者模式适用于数据结构相对稳定的系统 2)需要分离数据结构与处理时 |
参考:
https://www.runoob.com/w3cnote/state-vs-strategy.html