行为型模式
策略模式
定义: 定义了算法家族, 分别封装起来, 让它们之间可以互相替換, 此模式让算法的变化不会影响到使用算法的用户.
if…else…
适用场景:
- 系统很多分类, 而他们的区别仅仅在于他们的行为不同.
- 一个系统需要动态地在几种算法中选择一种.
优点:
- 开闭原则.
- 避免使用多重条件转移语句.
- 提高算法的保密性和安全性.
缺点:
- 客户端必须知道所有的策略类, 并自行决定使用哪一个策略类.
- 产生很多策略类.
相关设计模式
- 策略模式和工厂模式.
- 策略模式和状态模式.
Strategy Demo UML类图
JDK中使用策略模式的例子
抽象策略.Comparator
public class TreeMap<K,V>
extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, java.io.Serializable
{
}
Spring中使用策略模式的例子
org.springframework.core.io.Resource
下图都是一些实现Resource
的一些策略.
org.springframework.beans.factory.support.InstantiationStrategy
模板方法模式
定义: 定义了一个算法框架, 并允许子类为一个或多个步骤提供实现.
模板方法使得子类可以在不改变算法结构的情况下, 重新定义算法的某些步骤.
类型: 行为型
适用场景:
- 一次性实现一个算法不变的部分, 并将可变的行为留给子类来实现.
- 各子类中的公共的行为被提取出来并集中到一个公共的父类中, 从而避免代码重复.
优点:
- 提高复用性.
- 提高了扩展性.
- 符合开闭原则.
缺点:
- 类数目添加.
- 增加了系统实现的复杂度.
- 继承关系的自身缺点, 如果父类增加新的抽象方法, 所有子类都要修改.
扩展:
- 钩子方法
相关设计模式:
- 模板方法模式和工厂方法模式
- 模板方法模式和策略模式
Template Method Demo UML类图
JDK中使用模板模式的例子
AbstractList
AbstractSet
AbstractMap
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
// ....模板的代码, 需要实现的可以重写
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
boolean modified = false;
for (E e : c) {
add(index++, e);
modified = true;
}
return modified;
}
// ...
}
Tomcat使用模板代码的例子
HttpServlet
public abstract class HttpServlet extends GenericServlet {
//...
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String msg = lStrings.getString("http.method_get_not_supported");
sendMethodNotAllowed(req, resp, msg);
}
//...
}
Mybatis中使用模板代码的例子
BaseExecutor
public abstract class BaseExecutor implements Executor {
//...
protected abstract int doUpdate(MappedStatement ms, Object parameter) throws SQLException;
protected abstract List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException;
protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
throws SQLException;
protected abstract <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql)
throws SQLException;
//...
}
访问者模式
定义: 封装作用于某种数据结构(如Set/List/Map等)中各元素的操作.
可以在不改变各个元素的类的前提下, 定义作用于这些元素的操作.
类型: 行为型
适用场景:
- 一个数据结构(List/Map/Set等)包含很多类型对象.
- 数据结构和数据操作分离.
优点:
- 增加新的操作很容易, 增加新的访问者即可.
缺点:
- 增加新的数据结构困难
- 具体元素的变更比较麻烦
相关设计模式:
- 访问者模式和迭代器模式(都是基于某种数据结构, 访问者模式是对数据结构某种特殊的处理, 迭代器重点是遍历)
Visitor Demo UML类图
JDK中使用访问者模式的例子
java.nio.file.FileVisitor
Spring中使用访问者模式的例子
org.springframework.beans.factory.config.BeanDefinitionVisitor
观察者模式
定义: 定义了对象之间的一对多依赖, 让多个观察者对象同时监听某个主题对象, 当主题对象发生变化时, 它的所有依赖者(观察者)都会收到通知并更新.
类型: 行为型
适用场景:
- 关联行为场景, 建立一套触发机制.
优点:
- 观察者和被观察者之间建立了一个抽象的耦合.
- 观察者模式支持广播通信.
缺点:
- 观察者之间有过多的细节依赖, 提高时间消耗及程序复杂度.
- 使用要得当, 避免循环调用.
Observer UML类图
JDK中使用观察者模式的例子
java.awt.Event
java.util.EventListener
监听器的实现方式就是观察者模式的一种实现方式, 也有称之为发布订阅模式.
迭代器模式
定义: 定义提供一种方法, 顺序访问一个集合对象中的各个元素, 而又不暴露该对象的内部表示
类型: 行为型
适用场景:
- 访问一个集合的内容, 而不需要暴露它的内部表示.
- 为遍历不同的集合结构, 提供一个统一的接口.
优点:
- 分离了集合对象的遍历行为
缺点:
- 类的个数成对增加
相关设计模式
- 迭代器模式和访问者模式
Iterator Demo UML类图
JDK中使用迭代器模式的例子
通过Iterator
接口来找实现即可.
public interface Iterator<E> {
// ...
boolean hasNext();
E next();
// ...
}
Arrays
public class Arrays {
private static class ArrayItr<E> implements Iterator<E> {
private int cursor;
private final E[] a;
ArrayItr(E[] a) {
this.a = a;
}
@Override
public boolean hasNext() {
return cursor < a.length;
}
@Override
public E next() {
int i = cursor;
if (i >= a.length) {
throw new NoSuchElementException();
}
cursor = i + 1;
return a[i];
}
}
}
Mybatis中使用迭代器模式的例子
DefaultCursor
public class DefaultCursor<T> implements Cursor<T> {
// ...
@Override
public Iterator<T> iterator() {
if (iteratorRetrieved) {
throw new IllegalStateException("Cannot open more than one iterator on a Cursor");
}
if (isClosed()) {
throw new IllegalStateException("A Cursor is already closed.");
}
iteratorRetrieved = true;
return cursorIterator;
}
// ...
}
解释器模式
定义: 给定一个语言, 定义它的文法的一种表示, 并定义一个解释器, 这个解释器使用该表示来解释语言中的句子.
为了解释一门语言, 而为这门语言创建解释器.
类型: 行为型
适用场景:
- 某个特定类型的问题发生频率足够高的时候.
优点:
- 语法由很多表示, 容易改变及扩展此语言.
缺点:
- 当语法规则目录太多时, 增加了系统的复杂度.
相关设计模式
- 解释器模式和适配器模式
Interpreter Demo UML类图
JDK中使用解释器模式的例子
java.util.regex.Pattern
正则表达式解释器
Spring中使用解释器的例子
org.springframework.expression.ExpressionParser
责任链模式
定义: 为请求创建一个接收此次请求对象的链
类型: 行为型
适用场景:
- 一个请求的处理需要多个对象当中的一个或几个协作处理.
优点:
- 请求的发送者和接收者(请求的处理)解耦.
- 责任链可以动态组合.
缺点:
- 责任链太长或者处理时间过长, 影响性能.
- 责任链有可能过多.
相关设计模式
- 责任链模式和状态模式
Tomcat中使用责任链模式的例子
javax.servlet.Filter
// 责任链中的元素
public interface Filter {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException;
}
javax.servlet.FilterChain
public interface FilterChain {
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException;
}
ChainOfResponsibility UML 类图
中介者模式
定义: 定义一个封装一组对象如何交互的对象.
通过使对象明确地相互应用来促进松散耦合, 并允许独立地改变它们地交互.
类型: 行为型
适用场景:
- 系统中对象之间存在复杂的引用关系, 产生的相互依赖关系结构混乱且难以理解.
- 交互的公共行为, 如果需要改变行为则可以增加新的中介者类.(e.g.聊天室)
优点;
- 将一对多转化成一对一, 降低复杂度
- 类之间解耦
缺点:
- 中介者过多, 导致系统复杂
相关设计模式
- 中介者模式和观察者模式
Mediator Demo UML类图
JDK中使用中介者模式的例子
java.util.Timer
public class Timer {
// 通过 Timer 这个中介来协调 task 的执行 同事类
private void sched(TimerTask task, long time, long period) {
if (time < 0)
throw new IllegalArgumentException("Illegal execution time.");
// Constrain value of period sufficiently to prevent numeric
// overflow while still being effectively infinitely large.
if (Math.abs(period) > (Long.MAX_VALUE >> 1))
period >>= 1;
synchronized(queue) {
if (!thread.newTasksMayBeScheduled)
throw new IllegalStateException("Timer already cancelled.");
synchronized(task.lock) {
if (task.state != TimerTask.VIRGIN)
throw new IllegalStateException(
"Task already scheduled or cancelled");
task.nextExecutionTime = time;
task.period = period;
task.state = TimerTask.SCHEDULED;
}
queue.add(task);
if (queue.getMin() == task)
queue.notify();
}
}
}
状态模式
定义: 允许一个对象在其内部状态改变时, 改变它的行为.
类型: 行为型
适用场景:
- 一个对象存在多个状态(不同状态下行为不同), 且状态之间相互转换.
优点:
- 将不同状态隔离.
- 把各种状态的转换逻辑, 分布到State的子类当中, 减少相互依赖.
- 增加新的状态非常简单.
缺点:
- 状态多的业务场景导致类数目增加,系统变复杂.
相关设计模式:
- 状态模式和享元模式
State Demo UML类图
jsf中使用状态模式的例子
javax.faces.lifecycle.Lifecycle
public abstract class Lifecycle {
public abstract void execute(FacesContext context) throws FacesException;
}
备忘录模式
定义: 保存一个对象的某个状态, 以便在适当的时候恢复对象.
类型: 行为型
适用场景:
- 保存及恢复数据相关的业务场景.
- 需要恢复到之前状态的时候.
优点:
- 为用户提供一种可恢复的机制.
- 存档信息的封装.
缺点:
- 资源占用
相关设计模式
- 备忘录模式和状态模式
Memento Demo UML类图
Spring中使用备忘录模式的例子
org.springframework.binding.message.StateManageableMessageContext
public interface StateManageableMessageContext extends MessageContext {
/**
* Create a serializable memento, or token representing a snapshot of the internal state of this message context.
* @return the messages memento
*/
Serializable createMessagesMemento();
}
命令模式
定义: 将请求封装成对象, 以便使用不同的请求.
命令模式解决了应用程序中对象的职责以及它们之间的通信方式.
类型: 行为型
适用场景:
- 请求调用者和请求接收者需要解耦, 使得调用者和接收者不直接交互
- 需要抽象出等待执行的行为
优点:
- 降低耦合
- 容易扩展新命令或者一组命令
缺点:
- 命令的无限扩展会增加类的数量, 提高系统实现的复杂度.
相关设计模式:
- 命令模式和备忘录模式
Command Demo UML类图
JDK中使用命令模式的例子
java.lang.Runnable
实现此接口的都是具体的命令
JUnit中使用命令模式的例子
junit.framework.Test