抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

行为型模式

策略模式

定义: 定义了算法家族, 分别封装起来, 让它们之间可以互相替換, 此模式让算法的变化不会影响到使用算法的用户.

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

评论