设计模式——行为型模式
一:目录
1. 策略模式(Strategy)
2.状态模式(State)
3.责任链模式(Chain Of Responsibility)
4.解释器模式(Interpreter)
5.命令模式(Command)
6.观察者模式(Observer)
7.备忘录模式(Memento)
8.迭代器模式(Iterator)
9.模板方法模式(Template Method)
10.访问者模式(Visitor)
11.中介者模式(Mediator)
二:详细介绍
2.1 策略模式(Strategy)
2.1.1 简介:
策略模式的主要目的是将算法的定义与使用分开,也就是将算法的行为与环境分开,将算法的定义放在专门的策略类汇总,每一个策略类封装了一种实现算法,使用算法的环境类针对抽象策略类进行编程,符合“依赖倒转原则”。
2.1.2 类图:
角色:
Context(环境类):环境类是使用算法的角色,它在解决某个问题时可以采用多种策略。在环境类中维持一个对抽象策略类的引用实例,用于定义所采用的策略。
Strategy(策略接口类):它为所支持的算法声明了抽象方法,是所有策略类的父类,可以是接口、抽象类、具体类。
ConcreteStrategy(具体策略类):它实现了在抽象策略类中声明的算法,运行时覆盖策略接口类,使用某种具体算法实现业务处理
2.1.3 实例:
Java SE的容器布局管理器,不同的布局封装成策略类算法
2.2 状态模式(State)
2.2.1 概论:
状态模式用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题。
2.2.2 适用场景:
对象的行为依赖于它的状态(如某些属性值),状态的变化将导致行为的变化
在代码中包含大量和对象状态有关的条件语句,导致代码的可维护性和灵活性变差,不能方便的增加和删除状态,并且导致客户类与类库之间的耦合增强
2.2.3 优缺点:
优点:
- 封装了状态的转换原则,可以对状态转换代码进行集中管理,而不是分散在一个个业务方法中
- 将所有与某个状态有关的行为放到一个类中,只需要注入一个不同的状态对象即可使环境对象拥有不同的行为
- 允许状态转换逻辑与状态对象合成一体,而不是提供一个巨大的条件语句块
缺点:
- 状态模式必然会增加系统中类和对象的数量,导致运行开销增大;
- 状态模式的结构与实现都比较复杂,使用不当容易导致程序结构与代码的混乱,增加设计的难度;
- 状态模式对“开闭原则”支持不太好,增加新的状态需要修改负责状态维护的代码;
2.2.3 类图:
2.2.4 实例:
在工作流与游戏开发中有广泛应用
2.3 责任链模式(Chain Of Responsibility)
2.3.1 描述:
责任链模式是一种对象的行为模式。在责任链模式中,对象持有下家的引用而连接成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上哪个对象最终处理这个请求,使得系统可以在不影响客户端的情况下动态的重新组织和分配责任。
纯与不纯的责任链:
纯责任链:要么处理请求,要么交给下家处理;不允许具体处理对象承担了一部分责任之后,又向下传递;一个请求必须被某一个处理对象所接收
不纯的责任链:纯的责任链很少见,能看到的基本上都是不纯的。
例如:击鼓传花,花束在每个人之间传递,当鼓声停下来,花在谁手中,谁就要喝酒行令。
2.3.2 适用场景:
有多个对象可以处理同一个请求,具体哪个对象处理该请求待运行时刻在确定,客户端只需将请求提交到责任链上,不需要关心请求的处理对象是谁以及如何处理
在不明确指定接收者的情况下,向一组对象中的一个提交一个请求
可动态指定一组对象处理请求,客户端可以动态创建责任链来处理请求,还可以改变链中处理者之间的顺序
2.3.3 类图:
2.4 解释器模式(Interpreter)
2.2.3 描述:
解释器模式为自定义语言的设计和实现提供了一种解决方案,他用于定义一组文法规则并通过这组文法规则来解释语言中的句子。
优点:
易于改变和扩展文法。在解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制来改变或扩展文法;
每一条文法规则都可以表示为一个类,因此可以方便的实现一个简单的语言;
2.2.3 类图:
抽象表达式角色:声明一个所有的具体表达式角色都需要实现的抽象接口。这个接口主要是一个interpret()方法,称作解释操作
终结符表达式(Terminal Expression)角色:实现了抽象表达式角色所要求的接口,主要是interpret()方法;例如R=R1+R2,在里面R1和R2就是终结符,对应的解析R1和R2的解释器就是终结符表达式;
非终结符表达式(Nonterminal Expcession)角色:文法中每一条规则都需要一个具体的非终结符表达式,它一般是文法中的运算符或者其他关键字。例如公式R=R1+R2中,“+”就是非终结符,解析“+”的解释器就是一个非终结符表达式。
环境(Context)角色:这个角色的任务一般是用来存放文法中各个终结符所对应的具体值,比如R=R1+R2,我们给R1赋值100,给R2赋值200.这些信息需要存放到环境角色中,很多情况下使用Map做环境角色也就够了
2.5 命令模式(Command)
2.5.1 描述:
命令模式属于对象的行为模式,又称行动(Action)模式或者交易(Transaction)模式
命令模式把一个请求或者操作封装到一个对象中。命令模式允许系统使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供撤销、恢复功能
2.5.2 结构:
命令模式是对命令的封装。命令模式把发出命令的责任和执行命令的责任分割开,委派给不同的对象。
每一个命令都是一个操作:请求的一方发出请求要求执行一个操作;接收的一方收到请求,并执行操作。命令模式允许请求的一方与接收的一方独立开来,使得请求的一方不必知道接收的一方的接口,更不必知道请求如何接收,如何执行、何时执行、怎么被执行。
命令允许请求的乙方和接收请求的一方能够独立演化,从而具有以下的优点:
- 命令模式使新的命令很容易被加到系统里
- 允许接收请求的乙方决定是否要否决请求
- 较容易的设计一个命令队列
- 可以容易的实现对请求的撤销和恢复
- 在需要的情况下,可以较容易地将命令记入日志
命令模式涉及到5个角色,分别为:
- 客户端(Client)角色:创建一个具体命令(ConcreteCommand)对象并确定其接受者
- 命令(Command)角色:声明了一个所有具体命令类的抽象接口
- 具体命令(ConcreteCommand)角色:定义一个接收者与行为之间的弱耦合;实现execute()方法,负责调用接收者的相应操作。execute()方法通常叫做执行方法
- 请求者(Invoker)角色:负责调用命令对象执行请求,相关的方法叫做行动方法
- 接收者(Receiver)角色:负责具体实施和执行一个请求。任何一个类都可以成为接收者,实施和执行请求的方法叫做行动方法
2.5.3 结构:
命令模式的优点:
更松散的耦合:命令模式使得发起命令的对象–客户端,和具体实现命令的对象-接收者对象完全解耦,也就是说发起命令的对象完全不知道具体实现对象是谁,也不知道如何实现。
更动态的控制:命令模式把请求封装起来,可以动态地对它进行参数化、队列化和日志化等操作,从而使得系统更灵活。
很自然的复合命令:命令模式中的命令对象能够很容易的组合成复合命令,也就是宏命令,从而使系统操作更简单,功能更强大
更好的扩展性:由于发起命令的对象和具体的实现完全解耦,因此扩展新的命令就很容易,只需要实现新的命令对象,然后在装配的时候,把具体的实现对象设置到命令对象中,就可以使用这个命令对象,已有的实现完全不用变化。
2.5.4 类图:
2.5.4 代码:
interface Command {
void execute();
}
class ConcreteCommand implements Command {
private Receiver receiver;
public ConcreteCommand(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void execute() {
System.out.println(this.getClass().getName() + " execute.");
receiver.action();
}
}
class Invoker {
private Command command;
public Invoker(Command command) {
this.command = command;
}
public void action() {
System.out.println(getClass().getName() + " action.");
command.execute();
}
}
class Receiver {
public void action() {
System.out.println(getClass().getName() + " action.");
}
}
public class CommandClient {
public static void main(String[] args) {
Receiver receiver = new Receiver();
Command command = new ConcreteCommand(receiver);
Invoker invoker = new Invoker(command);
invoker.action();
}
}
2.6 观察者模式(Observer)
2.6.1 简介:
观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式,模型-视图(Model/View)模式,源-监听器(Source/Listener)模式或者从属者(Dependents)模式。
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主体对象。这个主体对象在状态上发生变化时,会通知所有观察者对象,使他们能够更新自己。
推模型和拉模型
在观察者模式中,分为推模型和拉模型
推模型:主题对象向观察者推送主题的详细信息,不管观察者是否需要,同送的信息通常是主体对象的部分或全部数据
拉模型:主体对象通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到主题对象中获取,相当于是观察者从主体对象中拉数据。一般这种模型的实现,会把主体对象自身通过update()方法传递给观察者,这样观察者需要数据的时候,就可以通过这个引用来获取了
2.6.2 类图:
2.6.3 代码:
interface Observer {
void update();
}
class ConcreteObserver implements Observer {
public ConcreteObserver(Subject subject) {
subject.addObserver(this);
}
@Override
public void update() {
System.out.println(getClass().getName() + " 得到通知.");
}
}
abstract class Subject {
Vector<Observer> observers = new Vector<>();
void addObserver(Observer observer) {
observers.addElement(observer);
}
void removeObserver(Observer observer) {
observers.remove(observer);
}
public abstract void change();
}
class ConcreteSubject extends Subject {
private String state;
@Override
public void change() {
System.out.println(getClass().getName() + " state changed.");
this.notifyObservers();
}
private void notifyObservers() {
if(!CollectionUtils.isEmpty(observers)) {
for(Observer observer : observers) {
observer.update();
}
}
}
}
public class ObserverClient {
public static void main(String[] args) {
Subject subject = new ConcreteSubject();
Observer observer = new ConcreteObserver(subject);
subject.change();
}
}
2.6.4 延伸:
Java从语言级别提供了Observer模式的实现,提供了一个接口(Observer)和一个类(Observable)
java.util.Observer
java.util.Observable
2.7 备忘录模式(Memento)
2.7.1 延伸:
备忘录模式又叫做快照模式(Snapshot Pattern)或Token模式,是对象的行为模式。
备忘录对象时一个用来存储另外一个对象内部状态的快照的对象。备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态capture住,并外部化,存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。备忘录模式常常与命令模式和迭代子模式一同使用。
2.7.2 类图:
2.7.3 延伸:
2.7.4 延伸:
2.8 迭代器模式(Iterator)
2.9 模板方法模式(Template Method)
2.10 访问者模式(Visitor)
2.11 中介者模式(Mediator)
上一篇: UVA - 297:Quadtrees
下一篇: Android O新特性和行为变更总结