设计模式学习笔记(4)——行为型设计模式

版权声明:本文为博主原创,未经博主允许不得转载。 https://blog.csdn.net/weixin_36904568/article/details/90141828

一:策略模式

1. 定义

定义算法族,将每一个算法封装到具有共同接口的独立的类中,让他们之间可以互相替换,让算法的变换独立于使用者。

2. 使用

  • 场景:通过公共接口的一个引用,在具体的场景下可以使用不同的策略
  • 策略:只需要定义公共方法,交给不同的实现类具体实现细节(算法)

(1)场景

package StrategyPattern;
/*
抽象场景
 */
public class Scene {
    Strategy strategy;
    /*
    动态改变策略
     */
    public void setStrategy(Strategy strategy){
        this.strategy = strategy;
    }
    /*
    场景无需关心具体的实现方法,只需要知道有这么个方法,委托给抽象类型来实现
     */
    public void solution(){
        strategy.solution();
    }
}

package StrategyPattern;
/*
具体场景A
 */
public class SceneA extends Scene {
    /*
    委托给A策略
     */
    public SceneA() {
        this.strategy = new StrategyA();
    }
}

package StrategyPattern;
/*
具体场景B
 */
public class SceneB extends Scene {
    /*
    委托给策略B实现
     */
    public SceneB(){
        this.strategy = new StrategyB();
    }
}

(2)策略

package StrategyPattern;
/*
抽象策略
 */
public interface Strategy {
    /*
    不同的解决方法
     */
    public void solution();
}

package StrategyPattern;

public class StrategyA implements Strategy {
    @Override
    public void solution() {
        System.out.println("solutionA");
    }
}

package StrategyPattern;

public class StrategyB implements Strategy {
    @Override
    public void solution() {
        System.out.println("solutionB");
    }
}

(3)在特定场景使用特定策略

public class Test {
    public static void main(String[] args) {
        Scene scene = new SceneA();
        scene.solution();
        scene = new SceneB();
        scene.solution();
    }
}

3. 特点

  • 算法的平等性:算法之间可以相互替换,所有的策略算法在实现上也是相互独立的
  • 策略的唯一性:运行期间,在每一个时刻只能使用一个具体的策略实现对象

优点:

  • 恰当使用继承可以把公共的代码移到父类里面,从而避免代码重复。
  • 避免使用多重条件(if-else)语句

缺点:

  • 只适用于客户端知道算法或行为的具体实现
  • 策略过多会造成冗余

二:观察者模式

1. 定义

又叫发布-订阅模式、模型-视图模式、源-监听器模式或从属者模式。定义了对象的一对多依赖,让多个观察者对象同时监听某一个主题对象。当主题对象改变状态时,所有依赖者会收到通知并更新

  • 主题:管理状态,在状态发生变化时,通知观察者
    • 推模型:主题对象向观察者推送主题的详细信息,不管观察者是否需要
    • 拉模型:如果观察者需要更具体的信息,由观察者主动到主题对象中获取
  • 观察者
    • 在注册/订阅了主题后,可以收到状态的更新
    • 取消订阅后,不会收到状态的更新

2. 实现

  • 抽象观察者:提供更新接口,在主题发生改变时更新
  • 具体观察者:订阅具体的主题,协调主题的状态
  • 抽象主题:注册、去除、通知观察者
  • 具体主题:保存具体状态

(1)主题

package ObservePattern;

import java.util.List;

/**
 *抽象主题
 */
public interface Subject {
    /**
     * 注册观察者
     * @param observer
     */
    public void registerObserver(Observer observer);
    /**
     * 去除观察者
     * @param observer
     */
    public void removeObserver(Observer observer);
    /**
     * 通知观察者,拉数据
     */
    public void notifyObserver();

    /**
     * 通知观察者,推数据
     * @param status
     */
    public void notifyObserver(Object status);
}

package ObservePattern;

import java.util.ArrayList;
import java.util.List;

/**
 * 具体的主题
 */
public class MainSubject implements Subject{

    //观察者列表
    private List<Observer> observers;

    //具体数据
    private Object status;

    public MainSubject(){
        observers = new ArrayList<>();
    }

    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObserver() {
        for (Observer observer:
             observers) {
            observer.update();
        }
    }

    @Override
    public void notifyObserver(Object status) {
        for (Observer observer:
                observers) {
            observer.update(status);
        }
    }

    //获取数据
    public Object getStatus() {
        return status;
    }

    //数据发生改变
    public void change(Object status){
        this.status = status;
        System.out.println("拉数据");
        notifyObserver();
        System.out.println("推数据");
        notifyObserver(status);
    }
}

(2)观察者

package ObservePattern;
/**
 * 抽象观察者
 */
public interface Observer {

    /**
     * 取消订阅主题
     */
    public void cancel();
    /**
     * 自己获取数据
     * @param
     */
    public void update();

    /**
     * 直接获取数据
     * @param status
     */
    public void update(Object status);
}

package ObservePattern;

/**
 * 具体观察者A
 */
public class ObserverA implements Observer {

    //具体状态
    private Object status;

    //具体主题
    private Subject subject;

    //订阅主题
    public ObserverA(Subject subject){
        this.subject = subject;
        subject.registerObserver(this);
    }

    //取消订阅
    @Override
    public void cancel() {
        subject.removeObserver(this);
    }

    @Override
    public void update() {
        if (subject instanceof MainSubject){
            this.status = ((MainSubject) subject).getStatus();
            System.out.println("自己拉数据,A知道状态改变了");
        }
    }

    @Override
    public void update(Object status) {
        this.status = status;
        System.out.println("主动推数据,A知道状态改变了");
    }
}

package ObservePattern;

/**
 * 具体观察者B
 */
public class ObserverB implements Observer {

    //具体状态
    private Object status;

    //具体主题
    private Subject subject;

    //订阅主题
    public ObserverB(Subject subject){
        this.subject = subject;
        subject.registerObserver(this);
    }

    //取消订阅
    @Override
    public void cancel() {
        subject.removeObserver(this);
    }

    @Override
    public void update() {
        if (subject instanceof MainSubject){
            this.status = ((MainSubject) subject).getStatus();
            System.out.println("自己拉数据,B知道状态改变了");
        }
    }

    @Override
    public void update(Object status) {
        this.status = status;
        System.out.println("主题推数据,B知道状态改变了");
    }
}

(3)测试

package ObservePattern;

public class Test {
    public static void main(String[] args) {
        Subject subject = new MainSubject();
        Observer observerA = new ObserverA(subject);
        Observer observerB = new ObserverB(subject);
        ((MainSubject) subject).change("test");

    }
}

3. 特点

  • 可以随时添加、删除观察者,无需修改主题
  • 可以独立使用主题或观察者
  • 有多个观察者时,通知顺序不一定相同

4. JAVA内置的支持

  • 主题——Observable类:发送通知
    • setChanged():标记状态改变
    • notifyObservers():通知,拉数据
    • notifyObservers(xxx):发送数据和通知,推数据
  • 观察者——Observer类:接收通知
    • update(Observale x):主题
    • update(Observale x,xxx):主题和数据

三:命令模式

1. 定义

又称为行动模式或交易模式。把一个请求或者操作封装到一个对象中,允许系统使用不同的请求把客户端参数化,对请求排队或者记录请求日志可以提供命令的撤销和恢复功能。

  • 发出命令的责任:请求的一方发出请求要求执行一个命令
  • 执行命令的责任:接收的一方收到请求,并执行操作
  • 由协调者在中间进行协调

使用

  • 具体接受者
    • 具体接受动作
  • 抽象命令接口
  • 具体命令对象
    • 使用堆栈记录过去的状态
    • 接受者
    • 公开执行方法(接受者需要执行的动作集合)
    • 公开撤销方法(状态出栈,接受者执行返回到该状态的对应动作集合)
  • 协调者
    • 使用堆栈记录过去的状态
    • 保存多个命令对象
    • 执行命令:命令对象中的函数
      • 调用接受者的动作
      • 当前的命令入栈
    • 撤销命令
      • 命令出栈,调用其撤销动作
  • 业务
    • 客户把封装了具体接受者的具体命令对象传递给调用者
    • 调用者执行命令(命令对象中的函数),调用接受者的动作

(1)接受者

package CommandPattern;

/**
 * 接受者A
 */
public class ReceiverA {

    public static final int MAX = 1;

    public static final int MIN = 0;

    //状态
    private int states;

    public ReceiverA(){
        this.states = MIN;
    }

    //操作
    public void actionToMax(){
        System.out.println("A接收到命令并将其变大");
        this.states = MAX;
    }

    //操作
    public void actionToMin(){
        System.out.println("A接收到命令并将其变小");
        this.states = MIN;
    }

    public int getStates() {
        return states;
    }
}

(2)命令

package CommandPattern;

/**
 * 抽象命令
 */
public interface Command {

    //执行命令
    public void execute();

    //撤销命令
    public void undo();
}

package CommandPattern;

import java.util.Stack;

/**
 * 具体命令A
 */
public class CommandA_MAX implements Command {

    private ReceiverA receiverA;

    private Stack<Integer> stack;

    public CommandA_MAX(ReceiverA receiverA) {
        this.receiverA = receiverA;
        stack = new Stack<>();
    }

    //让接受者执行相关的操作
    @Override
    public void execute() {
        //记录当前状态,方便撤销
        stack.push(receiverA.getStates());
        receiverA.actionToMax();
    }

    //让接受者撤销操作
    @Override
    public void undo() {
        int state = stack.pop();
        switch (state) {
            case ReceiverA.MIN:
                receiverA.actionToMin();
                break;
            case ReceiverA.MAX:
                receiverA.actionToMax();
                break;
        }
    }
}

package CommandPattern;

import java.util.Stack;

/**
 * 具体命令A
 */
public class CommandA_MIN implements Command {

    private ReceiverA receiverA;

    private Stack<Integer> stack;

    public CommandA_MIN(ReceiverA receiverA) {
        this.receiverA = receiverA;
        stack = new Stack<>();
    }

    //让接受者执行相关的操作
    @Override
    public void execute() {
        //记录当前状态,方便撤销
        stack.push(receiverA.getStates());
        receiverA.actionToMin();
    }

    //让接受者撤销操作
    @Override
    public void undo() {
        int state = stack.pop();
        switch (state) {
            case ReceiverA.MIN:
                receiverA.actionToMin();
                break;
            case ReceiverA.MAX:
                receiverA.actionToMax();
                break;
        }
    }
}

(3)协调者

package CommandPattern;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

/**
 * 协调者
 */
public class Invoker {

    private List<Command> commands;

    private Stack<Command> stack;

    public Invoker(){
        stack = new Stack<>();
        commands = new ArrayList<>();
    }

    public void setCommand(Command command) {
        commands.add(command);
    }

    //执行对应的命令
    public void invoke(int i){
        Command command = commands.get(i);
        stack.push(command);
        command.execute();
    }

    //撤销命令
    public void unInvoke(){
        Command command = stack.pop();
        command.undo();
    }
}

(4)测试

package CommandPattern;

public class Test {
    public static void main(String[] args) {
        ReceiverA receiverA = new ReceiverA();
        CommandA_MAX commandA_max = new CommandA_MAX(receiverA);
        CommandA_MIN commandA_min = new CommandA_MIN(receiverA);
        Invoker invoker = new Invoker();
        invoker.setCommand(commandA_max);
        invoker.setCommand(commandA_min);
        invoker.invoke(0);
        invoker.unInvoke();
        invoker.invoke(1);
        invoker.unInvoke();
    }
}

3. 特点

  • 容易扩展新的命令
  • 较容易地设计一个命令队列
  • 容易地实现对请求的撤销和恢复
  • 较容易地将命令记入日志

4. 宏命令

宏命令作为一个包含了一组具体命令的具体命令

  • 在执行宏命令时,执行它包含的所有命令
  • 在撤销宏命令时,撤销它包含的所有命令
package CommandPattern;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

/**
 * 宏命令,一次性执行所有命令
 */
public class MacroCommand implements Command{

    private List<Command> commands;

    private Stack<Command> stack;

    public MacroCommand(){
        commands = new ArrayList<>();
        stack = new Stack<>();
    }

    public void setCommand(Command command) {
        commands.add(command);
    }

    @Override
    public void execute() {
        for (Command command:
             commands) {
            command.execute();
            stack.push(command);
        }
    }

    @Override
    public void undo() {
        while (!stack.isEmpty()){
            Command command = stack.pop();
            command.undo();
        }
    }
}

5. 队列请求

工作队列存放一系列命令,线程从队列中取出命令并执行,然后再执行下一条命令
可以有效限制线程数目

6. 日志请求

  • 命令在执行的时候,通过记录方式,将日志存储在磁盘上
  • 系统异常时,命令利用磁盘的日志,通过加载方式,重新加载对象并执行命令

四:模板方法模式

1. 定义

在一个方法中定义一个算法的骨架,将一些步骤延迟到子类实现。子类在不改变算法结构的基础上,为一个或多个步骤重新定义

2. 使用

  • 抽象模板
    • 模板方法:每一个步骤都是一个业务方法
    • 具体业务方法(具有共性的)
      • 不可覆盖方法
      • 可覆盖方法(钩子):抽象类提供默认实现,子类可以选择性的扩展算法、控制算法
    • 抽象业务方法(具有个性的)
  • 具体实现类
    • 具体业务方法

模板

package TemplatePattern;

/**
 * 抽象模板
 */
public abstract class Template {

    //算法
    public final void operate(){
        operateA();
        operateB();
        operateC();
    }

    //具体不可覆盖实现
    public final void operateA(){
        System.out.println("步骤A");
    }

    //具体可覆盖实现(钩子)
    public void operateB(){
        System.out.println("步骤B");
    }

    //子类实现
    public abstract void operateC();
}

实现

package TemplatePattern;

/**
 * 具体实现模板A
 */
public class SubTemplateA extends Template{

    //自定义方法
    @Override
    public void operateC() {
        System.out.println("步骤C(子模板A)");
    }
}

package TemplatePattern;
/**
 * 具体实现模板B
 */
public class SubTemplateB extends Template {

    public void operateB(){
        System.out.println("步骤B(子模板B)");
    }

    @Override
    public void operateC() {
        System.out.println("步骤C(子模板B)");
    }
}

测试

package TemplatePattern;

public class Test {
    public static void main(String[] args) {
        Template template = new SubTemplateA();
        template.operate();

        template = new SubTemplateB();
        template.operate();
    }
}

3. 特点

  • 容易修改算法
  • 算法可以复用

五:迭代模式

1. 定义

又叫游标模式。顺序地访问一个聚集中的元素而不必暴露聚集的内部表象

  • hasNext():是否还有下一项
  • next():获取下一项
  • remove():删除当前一项

2. 使用

(1)白箱聚集与外禀迭代器

白箱聚集:提供宽接口的聚集(暴露聚集元素)。聚集对象向外界提供宽接口,破坏聚集对象的封装

外禀迭代器:由于聚集自己实现迭代逻辑,并向外部提供适当的宽接口,使得迭代器可以直接从外部控制聚集元素的迭代过程

  • 抽象聚集:创建迭代器对象的接口
  • 具体聚集:创建具体迭代器对象,提供聚集元素(白箱)
  • 抽象迭代器:遍历元素所需的接口
  • 具体迭代器:保持迭代过程中的游标位置
  • 客户:通过抽象迭代器访问抽象聚集,迭代器可以通过宽接口修改里面的元素
聚集
package IteratorPattern.ExtrinsicIterator;

/**
 * 抽象聚集
 */
public interface Aggregate {
    public Iterator createIterator();
}

package IteratorPattern.ExtrinsicIterator;

/**
 * 具体聚集
 */
public class ConcreteAggregate implements Aggregate{

    private Object[] objects;

    public ConcreteAggregate(Object[] objects){
        this.objects = objects;
    }

	//暴露自己的元素
    @Override
    public Iterator createIterator() {
        return new ConcreteIterator(this);
    }

    public int size(){
        return objects.length;
    }

    public Object getElement(int index){
        if (index < 0 || index > size()-1)
            throw new RuntimeException("越界!");
        return objects[index];
    }
}

迭代器
package IteratorPattern.ExtrinsicIterator;

/**
 * 自己实现的抽象迭代器
 */
public interface Iterator {

    public Object next();

    public boolean hasNext();

    public void first();
}

package IteratorPattern.ExtrinsicIterator;

/**
 * 具体迭代器
 */
public class ConcreteIterator implements Iterator{

    private ConcreteAggregate aggregate;

    private int index = 0;

    public ConcreteIterator(ConcreteAggregate aggregate){
        this.aggregate = aggregate;
        this.index = 0;
    }

    @Override
    public Object next() {
        return aggregate.getElement(index++);
    }

    @Override
    public boolean hasNext() {
        return index != aggregate.size();
    }

    @Override
    public void first() {
        index = 0;
    }
}

测试
package IteratorPattern.ExtrinsicIterator;

public class Test {
    public static void main(String[] args) {
        Object[] objArray = {"One","Two","Three","Four","Five","Six"};
        Aggregate aggregate = new ConcreteAggregate(objArray);
        Iterator iterator = aggregate.createIterator();
        while (iterator.hasNext())
            System.out.println(iterator.next());
    }
}

(2)黑箱聚集与内禀迭代器

黑箱聚集:提供窄接口的聚集。聚集对象的内部结构对迭代子对象适当公开,同时保证聚集对象的封装和迭代子功能

内禀迭代器: 由于迭代器是聚集的内部类,可以自由访问聚集的元素,所以迭代器可以自行实现迭代功能并控制对聚集元素的迭代逻辑

  • 抽象聚集:创建迭代器对象的接口
  • 抽象迭代器:遍历元素所需的接口
  • 具体聚集:创建具体迭代器对象,提供内部的具体迭代器(黑箱)
    • 具体迭代器:保持迭代过程中的游标位置
  • 客户:通过抽象迭代器访问抽象聚集,迭代器可以通过宽接口修改里面的元素
聚集
package IteratorPattern.IntrinsicIterator;

/**
 * 抽象聚集
 */
public interface Aggregate {
    public Iterator createIterator();
}

package IteratorPattern.IntrinsicIterator;

/**
 * 具体聚集
 */
public class ConcreteAggregate implements Aggregate {

    private Object[] objects;

    public ConcreteAggregate(Object[] objects){
        this.objects = objects;
    }

    @Override
    public Iterator createIterator() {
        return new ConcreteIterator();
    }

    public int size(){
        return objects.length;
    }

    public Object getElement(int index){
        if (index < 0 || index > size()-1)
            throw new RuntimeException("越界!");
        return objects[index];
    }

    /**
     * 内部迭代器
     */
    private class ConcreteIterator implements Iterator{

        private int index;

        @Override
        public Object next() {
            return getElement(index++);
        }

        @Override
        public boolean hasNext() {
            return index != size();
        }

        @Override
        public void first() {
            index = 0;
        }
    }
}

迭代器
package IteratorPattern.IntrinsicIterator;

/**
 * 自己实现的抽象迭代器
 */
public interface Iterator {

    public Object next();

    public boolean hasNext();

    public void first();
}

测试
package IteratorPattern.IntrinsicIterator;

public class Test {
    public static void main(String[] args) {
        Object[] objArray = {"One","Two","Three","Four","Five","Six"};
        Aggregate aggregate = new ConcreteAggregate(objArray);
        Iterator iterator = aggregate.createIterator();
        while (iterator.hasNext())
            System.out.println(iterator.next());
    }
}

(3)内部(被动)迭代

由迭代器自己来控制迭代下一个元素的步骤,在迭代的过程中,客户端需要把操作传递给迭代器,迭代器在迭代的时候会在每个元素上执行这个操作。

(4)外部(主动)迭代

由客户端来控制迭代下一个元素的步骤,客户端会明显调用迭代器的等迭代方法,在遍历过程中向前进行。

(5)静态迭代

迭代器由聚集对象创建,并持有聚集对象的一份快照,在产生后这个快照的内容就不再变化。客户端可以继续修改原聚集的内容,但是迭代器不会反映出聚集的新变化。

  • 易于实现
  • 对时间和内存资源的消耗

(6)动态迭代

迭代器被产生之后保持着对聚集元素的引用,因此,任何对原聚集内容的修改都会在迭代器上反映出来。

3. 特点

  • 简化了聚集的接口
  • 迭代器可以多态处理各种聚集
  • 封装聚集的具体内容

六:状态模式

1. 定义

又称状态对象模式。允许对象在内部状态改变时改变它的行为,看起来好像修改了它的类

2. 使用

  • 上下文(状态机)
    • 定义所有的状态
    • 记录当前状态
    • 定义客户端所感兴趣的接口(委托给状态接口实现),通过对某些属性值的判断,静态改变状态
  • 状态接口:定义所有的动作
  • 具体状态类:每个状态具体的处理动作,根据环境对象中的属性值,动态改变状态

上下文

package StatePattern;

/**
 * 上下文
 */
public class Context {

    //定义所有状态
    private StateA stateA;

    private StateB stateB;

    //当前状态
    private State state;

    public Context(){
        stateA = new StateA(this);
        stateB = new StateB(this);
        state = stateA;
    }

    //业务接口
    public void requestA(){
        state.operateA();
        state.operateB();
        //静态转换状态
        setState(stateB);
    }

    public void requestB(){
        state.operateA();
        state.operateB();
    }



    public StateA getStateA() {
        return stateA;
    }

    public StateB getStateB() {
        return stateB;
    }

    public State getState() {
        return state;
    }

    public void setState(State state) {
        this.state = state;
    }


}

状态

package StatePattern;

/**
 * 抽象状态
 */
public abstract class State {

    //抽象业务方法的默认实现
    public void operateA(){
        System.out.println("抱歉,不能使用A");
    }

    //抽象业务方法的默认实现
    public void operateB(){
        System.out.println("抱歉,不能使用B");
    }
}

package StatePattern;

/**
 * 具体状态
 */
public class StateA extends State {

    private Context context;

    public StateA(Context context){
        this.context = context;
    }

    //具体业务方法
    public void operateA(){
        System.out.println("使用A");
    }
}

package StatePattern;

/**
 * 具体状态
 */
public class StateB extends State {

    private Context context;

    public StateB(Context context){
        this.context = context;
    }

    //具体业务方法
    public void operateB(){
        System.out.println("使用B");
        //动态转换状态
        context.setState(context.getStateA());
    }
}

测试

package StatePattern;

public class Test {
    public static void main(String[] args) {
        System.out.println("此时默认状态为A");
        Context context = new Context();
        context.requestA();
        System.out.println("此时静态转换状态为B");
        context.requestB();
        System.out.println("此时动态转换状态为A");
        context.requestA();
    }
}

3. 特点

  • 可以分离状态的行为,通过维护状态的变化,来调用不同状态对应的不同功能
  • 状态模式的行为是平行性的,不可相互替换的;而策略模式的行为是平等性的,是可以相互替换的

七:责任链模式

1. 定义

很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。责任链可能是一条直线、一个环链或者一个树结构的一部分。

2. 使用

  • 抽象处理者:定义出一个处理请求的接口
  • 具体处理者:接到请求后,可以将请求处理掉,或者将请求传给下一个

(1)处理器

package ChainOfResponsibilityPattern;

/**
 * 抽象处理器
 */
public abstract class Handler {

    //下一个对象
    private Handler next;

    //处理业务
    public abstract void handler(String text);

    public Handler getNext() {
        return next;
    }

    public void setNext(Handler next) {
        this.next = next;
    }
}

package ChainOfResponsibilityPattern;

/**
 * 具体处理类
 */
public class HandlerA extends Handler {

    @Override
    public void handler(String text) {
        //可以处理
        if (text.startsWith("A"))
            System.out.println("开始对A类业务的处理");
        //不可以处理
        else{
            Handler handler = getNext();
            if (handler == null){
                System.out.println("已经没有对象了");
                return;
            }
            //传递给下一个对象
            else
                handler.handler(text);
        }
    }
}

package ChainOfResponsibilityPattern;

/**
 * 具体处理类
 */
public class HandlerB extends Handler {

    @Override
    public void handler(String text) {
        //可以处理
        if (text.startsWith("B"))
            System.out.println("开始对B类业务的处理");
            //不可以处理
        else{
            Handler handler = getNext();
            if (handler == null){
                System.out.println("已经没有对象了");
                return;
            }
            //传递给下一个对象
            else
                handler.handler(text);
        }
    }
}

(2)测试

package ChainOfResponsibilityPattern;

public class Test {
    public static void main(String[] args) {
        Handler handlerA = new HandlerA();
        Handler handlerB = new HandlerB();
        handlerA.setNext(handlerB);
        System.out.println("处理A型事务");
        handlerA.handler("A");
        System.out.println("处理B型事务");
        handlerA.handler("B");
        System.out.println("处理C型事务");
        handlerA.handler("C");
    }
}

3. 特点

  • 请求的发送者和接受者解耦
  • 系统可以在不影响客户端的情况下重新组织和分配责任(对责任链进行修改)
  • 不容易观察运行时的特征
  • 并不保证请求一定会被执行

八:解释器模式

1. 定义

给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器。客户端可以使用这个解释器来解释这个语言中的句子

2. 使用

  • 抽象表达式:定义解释的方法
  • 终结符表达式:特殊符号
  • 非终结符表达式:常量
  • 上下文:存放文法中各个终结符所对应的具体值
package InterpreterPattern;

import java.util.HashMap;
import java.util.Map;

/**
 * 上下文的环境,存储符号对应的整数值
 */
public class Context {
    private HashMap<Variable,Integer> map;

    public Context() {
        this.map = new HashMap<>();
    }

    public void assign(Variable variable,int num){
        map.put(variable,num);
    }

    public int lookup(Variable variable){
        return map.get(variable);
    }
}

package InterpreterPattern;

/**
 * 抽象表达式
 */
public abstract class Exception {

    //抽象的解释方法
    public abstract int interpret(Context context);
}

package InterpreterPattern;

import java.util.Objects;

/**
 * 终结符表达式“常量”
 */
public class Variable extends Exception{

    private String name;

    public Variable(String name){
        this.name = name;
    }

    //获取符号对应的整数
    @Override
    public int interpret(Context context) {
        return context.lookup(this);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Variable variable = (Variable) o;
        return Objects.equals(name, variable.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name);
    }
}

package InterpreterPattern;

/**
 * 非终结符表达式“+”
 */
public class Add extends Exception{

    private Exception exception1;

    private Exception exception2;

    public Add(Exception exception1, Exception exception2) {
        this.exception1 = exception1;
        this.exception2 = exception2;
    }

    //相加
    @Override
    public int interpret(Context context) {
        return exception1.interpret(context)+exception2.interpret(context);
    }
}

package InterpreterPattern;

public class Test {
    public static void main(String[] args) {
        Context context = new Context();
        //声明变量
        Variable a = new Variable("a");
        Variable b = new Variable("b");
        //赋值
        context.assign(a,1);
        context.assign(b,2);
        //加起来
        Exception exception = new Add(a,b);
        System.out.println(exception.interpret(context));
    }
}

3. 特点

  • 容易扩展语言
  • 语法规则容易扩展方法
  • 可以处理脚本语言和编程语言
  • 在语法规则的数目过大时,应该使用编译器或解释器的产生器

九:中介者模式

1. 定义

又叫调停者模式。中介者包含了整个系统的控制逻辑,包装了对象之间相互作用的方式,使得这些对象(同事)不必相互明显引用。当这些对象中的某些对象之间的相互作用发生改变时,不会立即影响到其他对象(同事)之间的相互作用。从而保证这些相互作用可以彼此独立地变化。

2. 使用

  • 抽象中介者:定义出连接同事对象的接口和业务方法
  • 具体中介者:连接所有的具体同事类,并负责协调各同事对象的交互关系。
  • 抽象同事类:定义出连接中介者的接口
  • 具体同事类:实现自己的业务,在需要与其他同事通信的时候,与中介者通信
package MediatorPattern;

/**
 * 抽象中介者
 */
public interface Mediator {

    //中介者业务
    public void changed(Colleague colleague);

}

package MediatorPattern;

/**
 * 具体中介者
 */
public class ConcreteMediator implements Mediator {

    private ColleagueA a;

    private ColleagueB b;

    public void setA(ColleagueA a) {
        this.a = a;
    }

    public void setB(ColleagueB b) {
        this.b = b;
    }

    @Override
    public void changed(Colleague colleague) {
        if (colleague instanceof ColleagueA){
            b.receive();
        }
        else if (colleague instanceof ColleagueB){
            a.receive();
        }
    }
}

package MediatorPattern;

/**
 * 抽象同事
 */
public abstract class Colleague {

    private Mediator mediator;

    public Colleague(Mediator mediator) {
        this.mediator = mediator;
    }

    public Mediator getMediator() {
        return mediator;
    }
}

package MediatorPattern;

/**
 * 具体同事
 */
public class ColleagueA extends Colleague {

    private String name;

    public ColleagueA(Mediator mediator,String name) {
        super(mediator);
        this.name = name;
    }

    public void send() {
        System.out.println(this+"请求数据");
        getMediator().changed(this);
    }

    public void receive(){
        System.out.println(this+"收到数据");
    }

    @Override
    public String toString() {
        return "ColleagueA{" +
                "name='" + name + '\'' +
                '}';
    }
}

package MediatorPattern;

/**
 * 具体同事
 */
public class ColleagueB extends Colleague {

    private String name;

    public ColleagueB(Mediator mediator,String name) {
        super(mediator);
        this.name = name;
    }

    public void send() {
        System.out.println(this+"请求数据");
        getMediator().changed(this);
    }

    public void receive(){
        System.out.println(this+"收到数据");
    }

    @Override
    public String toString() {
        return "ColleagueB{" +
                "name='" + name + '\'' +
                '}';
    }
}

package MediatorPattern;

public class Test {
    public static void main(String[] args) {
        ConcreteMediator mediator = new ConcreteMediator();
        ColleagueA a = new ColleagueA(mediator,"A");
        ColleagueB b = new ColleagueB(mediator,"B");
        mediator.setA(a);
        mediator.setB(b);
        a.send();
        b.send();
    }
}

3. 特点

  • 将对象解耦,增加复用性
  • 集中控制逻辑
  • 减少对象之间的消息传递
  • 中介者可能过于复杂

十:备忘录模式

1. 定义

又叫做快照模式或Token模式。是一个用来存储对象内部状态的快照的对象,在不破坏封装的条件下,将一个对象的状态捕捉住并外部化,可以让对象还原到原状态。备忘录模式常常与命令模式和迭代子模式一同使用。

2. 使用

  • 备忘录类:将发起人对象的状态存储起来,保护发起人对象的内容
    • 窄接口:所有对象都可以读取数据
    • 宽接口:发起人对象可以读取数据
  • 发起人类:创建一个含有当前的内部状态的备忘录对象,使用备忘录对象存储
  • 负责人类:保存备忘录对象,不检查备忘录对象的内容
  • 客户端类:在发起人产生备忘录时使用负责人保存备忘录

(1)白箱

备忘录对任何对象都提供一个接口,即宽接口,备忘录角色的内部所存储的状态就对所有对象公开。

备忘录
package MementoPattern.white;

/**
 * 备忘录
 */
public class Memento {

    private String state;

    public Memento(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }
}

发起人
package MementoPattern.white;

/**
 * 发起者(持有状态)
 */
public class Originator {

    private String state;

    //存储状态
    public Memento getMemento(){
        return new Memento(state);
    }

    //载入状态
    public void restoreState(Memento memento){
        this.state = memento.getState();
    }

    public void setState(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }
}

负责人
package MementoPattern.white;

/**
 * 负责人(持有备忘录)
 */
public class Caretaker {

    private Memento memento;

    public Memento getMemento() {
        return memento;
    }

    public void setMemento(Memento memento) {
        this.memento = memento;
    }
}

测试
package MementoPattern.white;

public class Test {
    public static void main(String[] args) {
        Caretaker caretaker = new Caretaker();
        Originator originator = new Originator();
        originator.setState("状态A");
        System.out.println(originator.getState());
        //保存状态A
        caretaker.setMemento(originator.getMemento());
        originator.setState("状态B");
        System.out.println(originator.getState());
        //恢复状态A
        originator.restoreState(caretaker.getMemento());
        System.out.println(originator.getState());
    }
}

(2)黑箱

备忘录对发起人对象提供一个宽接口,而为其他对象提供一个窄接口。这样的实现叫做“黑箱实现”。(将备忘录类设计成发起人的内部成员类)

备忘录的窄接口
package MementoPattern.black;

/**
 * 窄接口,不提供方法
 */
public interface MementoIF {
}

发起人
package MementoPattern.black;

/**
 * 发起者(持有状态和备忘录)
 */
public class Originator {

    private String state;

    //存储状态
    public MementoIF getMemento(){
        return new Memento(state);
    }

    //载入状态
    public void restoreState(MementoIF memento){
        this.setState(((Memento)memento).getState());
    }

    public void setState(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }

    /**
     * 备忘录宽接口
     */
    private class Memento implements MementoIF{

        private String state;

        public Memento(String state) {
            this.state = state;
        }

        public String getState() {
            return state;
        }

        public void setState(String state) {
            this.state = state;
        }
    }
}

负责人
package MementoPattern.black;

/**
 * 负责人(持有备忘录的窄接口)
 */
public class Caretaker {

    private MementoIF memento;

    public MementoIF getMemento() {
        return memento;
    }

    public void setMemento(MementoIF memento) {
        this.memento = memento;
    }
}

测试
package MementoPattern.black;

public class Test {
    public static void main(String[] args) {
        Caretaker caretaker = new Caretaker();
        Originator originator = new Originator();
        originator.setState("状态A");
        System.out.println(originator.getState());
        //保存状态A
        caretaker.setMemento(originator.getMemento());
        originator.setState("状态B");
        System.out.println(originator.getState());
        //恢复状态A
        originator.restoreState(caretaker.getMemento());
        System.out.println(originator.getState());
    }
}

(3)多节点

备忘录模式可以将发起人对象恢复到备忘录对象所存储的某一个检查点上

备忘录
package MementoPattern.many;

import java.util.ArrayList;
import java.util.List;

/**
 * 备忘录
 */
public class Memento {

    //发起人此时的所有状态
    private List<String> states;

    //发起人此时的状态数量
    private int index;

    public Memento(List<String> states, int index) {
        this.states = new ArrayList<>(states);
        this.index = index;
    }

    public List<String> getStates() {
        return states;
    }

    public int getIndex() {
        return index;
    }

    @Override
    public String toString() {
        return "Memento{" +
                "states=" + states +
                ", index=" + index +
                '}';
    }
}

发起人
package MementoPattern.many;

import java.util.ArrayList;
import java.util.List;

package MementoPattern.many;

import java.util.ArrayList;
import java.util.List;

/**
 * 发起者(持有状态)
 */
public class Originator {

    //当前所有的状态
    private List<String> states;

    //当前的状态数量
    private int index;

    public Originator() {
        states = new ArrayList<>();
        index = 0;
    }

    //存储状态
    public Memento getMemento(){
        return new Memento(states,index);
    }

    //载入状态
    public void restoreState(Memento memento){
        states = memento.getStates();
        index = memento.getIndex();
    }

    //进入新状态
    public void setState(String state){
        states.add(state);
        index++;
    }

    public void printStates(){
        for (String state:
             states) {
            System.out.printf("%s ",state);
        }
        System.out.printf("\n");
    }
}

执行者
package MementoPattern.many;

import java.util.ArrayList;
import java.util.List;

/**
 * 负责人(持有备忘录)
 */
public class Caretaker {

    //所有备忘录
    private List<Memento> mementos;

    //检查点
    private int current;

    //发起人
    private Originator originator;

    public Caretaker(Originator originator) {
        this.originator = originator;
        mementos = new ArrayList<>();
        current = 0;
    }

    //创建新的存储点
    public int createMemento(){
        Memento memento = originator.getMemento();
        System.out.println(memento);
        mementos.add(memento);
        return current++;
    }

    //载入之前某个存储点
    public void restore(int index){
        Memento memento = mementos.get(index);
        originator.restoreState(memento);
    }

    //去掉存储点
    public void remove(int index){
        mementos.remove(index);
    }

}


package MementoPattern.many;

public class Test {
    public static void main(String[] args) {
        Originator originator = new Originator();
        Caretaker caretaker = new Caretaker(originator);
        originator.setState("状态A");
        originator.printStates();
        //保存状态A
        int index1 = caretaker.createMemento();
        originator.setState("状态B");
        originator.printStates();
        //保存状态A和B
        int index2 = caretaker.createMemento();
        //恢复状态A
        caretaker.restore(index1);
        originator.printStates();
        //恢复状态B
        caretaker.restore(index2);
        originator.printStates();
    }
}

(4)“自述历史”模式

客户端兼任负责人

  • 备忘录类:将发起人对象的状态存储起来,保护发起人对象的内容
  • 发起人类:创建一个含有当前的内部状态的备忘录对象,使用备忘录对象存储
  • 客户端: 负责保持备忘录对象
package MementoPattern.HistoryOnSelf;

import MementoPattern.black.Caretaker;
import MementoPattern.many.Memento;

public class Test {
    public static void main(String[] args) {
        Originator originator = new Originator();
        originator.setState("状态A");
        System.out.println(originator.getState());
        //保存状态A
        MementoIF memento = originator.getMemento();
        originator.setState("状态B");
        System.out.println(originator.getState());
        //恢复状态A
        originator.restoreState(memento);
        System.out.println(originator.getState());
    }
}

3. 特点

  • 维护对象内聚
  • 保持关键对象的数据封装
  • 提供容易实现的恢复功能
  • 存储和恢复状态耗时

十一:访问者模式

1. 定义

封装一些施加于某种数据结构元素之上的操作,在修改操作时数据结构保持不变。把数据结构和作用于结构上的操作之间解耦

分派:

根据对象的类型而对方法进行的选择,就是分派

对象的类型:

  • 静态类型:变量被声明时的类型
  • 实际类型:变量所引用的对象的真实类型

分派的类型:

  • 静态分派:发生在编译时期,分派根据静态类型信息发生(方法重载)
  • 动态分派:发生在运行时期,分派动态地置换掉某个方法(方法重写)
  • 单分派:仅仅会考虑到方法的接收者的类型
  • 多分派:考虑方法的接受者和参数等

双重分派:在Java中可以通过两次方法调用来达到两次分派的目的

2. 使用

数据结构的每一个节点都可以接受一个访问者的调用,节点向访问者对象传入自身,访问者对象同时也反过来执行节点对象的操作。这样的过程叫做“双重分派”

  • 抽象访问者:对每个具体节点的访问方法
  • 具体访问者:实现具体的访问方法
  • 抽象节点:接受访问者对象的调用
  • 具体节点:实现了接受操作和自己的业务逻辑
  • 结构对象:遍历结构中的所有元素

(1)访问者

package VisitorPattern;

/**
 * 抽象访问者
 */
public interface Visitor {

    public void visit(NodeA node);

    public void visit(NodeB node);
}

package VisitorPattern;

/**
 * 具体访问者A
 */
public class ConcreteVisitor implements Visitor {
    @Override
    public void visit(NodeA node) {
        System.out.println("第二重分派——不同的结点");
        node.operateA();
    }

    @Override
    public void visit(NodeB node) {
        System.out.println("第二重分派——不同的结点");
        node.operateB();
    }
}

(2)节点

package VisitorPattern;

/**
 * 抽象结点
 */
public interface Node {

    public void accept(Visitor visitor);
}

package VisitorPattern;

/**
 * 具体结点A
 */
public class NodeA implements Node {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }

    //特定业务
    public void operateA(){
        System.out.println("A结点的业务方法");
    }
}

package VisitorPattern;

/**
 * 具体结点B
 */
public class NodeB implements Node {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }

    //特定业务
    public void operateB(){
        System.out.println("B结点的业务方法");
    }
}

(3)数据结构

package VisitorPattern;

import java.util.ArrayList;
import java.util.List;

/**
 * 数据结构
 */
public class Structure {

    //保存结点
    private List<Node> nodes;

    public Structure() {
        nodes = new ArrayList<>();
    }

    public void add(Node node){
        nodes.add(node);
    }

    public void remove(int index){
        nodes.remove(index);
    }

    //遍历操作结点
    public void action(Visitor visitor){
        System.out.println("第一重分配——不同的访问者");
        for (Node node:
             nodes) {
            node.accept(visitor);
        }
    }
}

(4)测试

package VisitorPattern;

public class Test {
    public static void main(String[] args) {
        Structure structure = new Structure();
        Node a = new NodeA();
        Node b = new NodeB();
        structure.add(a);
        structure.add(b);
        Visitor visitor = new ConcreteVisitor();
        structure.action(visitor);
    }
}

3. 特点

  • 能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能
  • 可以通过访问者来定义整个对象结构通用的功能,从而提高复用程度
  • 可以通过访问者来分离无关的行为
  • 破坏组合结构的包装

猜你喜欢

转载自blog.csdn.net/weixin_36904568/article/details/90141828