设计模式——行为型

一、模板模式

        模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern),在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。简单说,模板方法模式定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定步骤。

模板模式角色

AbstractClass:抽象类中实现了模板方法,定义了算法的骨架,具体子类需要去实现其抽象方法或者重写其中的方法。

ConcreteClass:实现了抽象方法,已完成算法中特定子类的步骤

模板模式UML图

应用实例

制作豆浆的流程如下:

  • 制作豆浆的流程选材 ----> 添加配料 ----> 浸泡 ----> 放到豆浆机打碎
  • 通过添加不同的配料,可以制作出不同口味的豆浆
  • 选材、浸泡和放到豆浆机打碎这几个步骤对于制作每种口味的豆浆都是一样的

抽象类

package com.taoke.designPattern.template;

/**
 * 抽象类,表示豆浆
 *
 * @author taoke
 * @date 2022/7/22
 */
public abstract class SoyMilk {

    final void make() {
        select();
        addCondiment();
        soak();
        beat();
    }


    /**
     * 选材料
     */
    void select() {
        System.out.println("挑选新鲜的豆子!");
    }

    /**
     * 添加不同的调料,子类实现
     */
    abstract void addCondiment();

    /**
     * 浸泡
     */
    void soak() {
        System.out.println("将豆子浸泡3小时!");
    }

    void beat() {
        System.out.println("将调料和豆子放入豆浆机,并打碎!");
    }

}

子类

package com.taoke.designPattern.template;

/**
 * 花生豆将
 *
 * @author taoke
 * @date 2022/7/22
 */
public class PeanutSoyMilk extends SoyMilk {

    @Override
    void addCondiment() {
        System.out.println("加入上好的花生!");
    }

}

package com.taoke.designPattern.template;

/**
 * 红豆豆浆
 *
 * @author taoke
 * @date 2022/7/22
 */
public class RedBeanSoyMilk extends SoyMilk {

    @Override
    void addCondiment() {
        System.out.println("加入上好的红豆!");
    }
}

测试类

package com.taoke.designPattern.template;

/**
 * 模板方法模式测试类
 *
 * @author taoke
 * @date 2022/7/22
 */
public class TemplateTest {
    public static void main(String[] args) {
        System.out.println("-------制作红豆豆浆-------");
        SoyMilk redBeanSoyMilk = new RedBeanSoyMilk();
        redBeanSoyMilk.make();
        System.out.println("-------制作花生豆浆-------");
        SoyMilk peanutSoyMilk = new PeanutSoyMilk();
        peanutSoyMilk.make();
    }
}

二、命令模式

1)命令模式(Command Pattern):在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可。此时可以使用命令模式来进行设计

2)命令模式使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活,实现解耦

3)在命令模式中,会将一个请求封装为一个对象,以便使用不同参数来表示不同的请求(即命名),同时命令模式也支持可撤销的操作

4)通俗易懂的理解:将军发布命令,士兵去执行。其中有几个角色:

  • 将军(命令发布者)、士兵(命令的具体执行者)、命令(连接将军和士兵)
  • Invoker是调用者(将军),Receiver是被调用者(士兵),MyCommand是命令,实现了Command接口,持有接收对象

命令模式的角色

Invoker:调用者角色,只需要发布命令就可以控制接收者的行为

Receiver:接收者角色,知道如何实施执行请求的相关操作

Command:命令角色,需要执行的所有命令都定义在这里,可以是接口或者抽象类

ConcreteCommand:具体的命令角色,将一个接收者和一个动作绑定,调用接收者相应的操作,实现execute

命令模式UML图

应用实例

  • 我们买了一套智能家电,有照明灯、风扇、冰箱、洗衣机,只要在手机上安装 APP 就可以控制这些家电的工作
  • 这些智能家电来自不同的厂家,我们不想针对每一种家电都安装一个 APP 分别控制,我们希望只要一个 APP 就可以控制全部智能家电
  • 要实现一个 APP 控制所有智能家电的需要,则每个智能家电厂家都要提供一个统一的接口给 APP 调用,这时就可以考虑使用命令模式
  • 命令模式可将“动作的请求者”从“动作的执行者”对象中解耦出来
  • 在我们的例子中,动作的请求者是手机 APP,动作的执行者是每个厂商的一个家电产品

UML图

命令角色

package com.taoke.designPattern.command;

/**
 * 创建命令接口
 *
 * @author taoke
 * @date 2022/7/22
 */
public interface Command {

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

    /**
     * 撤销命令
     */
    void undo();

}

具体命令角色

package com.taoke.designPattern.command;

/**
 * 开灯命令
 *
 * @author taoke
 * @date 2022/7/22
 */
public class LightOnCommand implements Command {

    private final LightReceiver receiver;

    public LightOnCommand(LightReceiver receiver) {
        this.receiver = receiver;
    }

    @Override
    public void execute() {
        receiver.on();
    }

    @Override
    public void undo() {
        receiver.off();
    }
}

package com.taoke.designPattern.command;

/**
 * 关灯命令
 *
 * @author taoke
 * @date 2022/7/22
 */
public class LightOffCommand implements Command {

    private final LightReceiver receiver;

    public LightOffCommand(LightReceiver receiver) {
        this.receiver = receiver;
    }

    @Override
    public void execute() {
        receiver.off();
    }

    @Override
    public void undo() {
        receiver.on();
    }
}

package com.taoke.designPattern.command;

/**
 * 开电视机命令
 *
 * @author taoke
 * @date 2022/7/22
 */
public class TVOnCommand implements Command {

    private final TVReceiver receiver;

    public TVOnCommand(TVReceiver receiver) {
        this.receiver = receiver;
    }

    @Override
    public void execute() {
        receiver.on();
    }

    @Override
    public void undo() {
        receiver.off();
    }
}

package com.taoke.designPattern.command;

/**
 * 关闭电视机命令
 *
 * @author taoke
 * @date 2022/7/22
 */
public class TVOffCommand implements Command {

    private final TVReceiver receiver;

    public TVOffCommand(TVReceiver receiver) {
        this.receiver = receiver;
    }

    @Override
    public void execute() {
        receiver.off();
    }

    @Override
    public void undo() {
        receiver.on();
    }
}

package com.taoke.designPattern.command;

/**
 * 空命令
 *
 * @author taoke
 * @date 2022/7/22
 */
public class NoCommand implements Command{

    @Override
    public void execute() {

    }

    @Override
    public void undo() {

    }
}

调用者

package com.taoke.designPattern.command;

/**
 * 遥控器
 *
 * @author taoke
 * @date 2022/7/22
 */
public class RemoteController {

    /**
     * 开 按钮的命令组
     */
    Command[] onCommands;
    /**
     * 关 按钮的命令组
     */
    Command[] offCommands;
    /**
     * 执行撤销的命令
     */
    Command undoCommand;

    public RemoteController() {
        onCommands = new Command[5];
        offCommands = new Command[5];

        for (int i = 0; i < 5; i++) {
            onCommands[i] = new NoCommand();
            offCommands[i] = new NoCommand();
        }
    }

    public void setCommands(int no, Command onCommand, Command offCommand) {
        onCommands[no] = onCommand;
        offCommands[no] = offCommand;
    }

    /**
     * 按下开按钮
     *
     * @param no 编号
     */
    public void onButtonPushed(int no) {
        //找到按下的开按钮,并调用相应方法
        onCommands[no].execute();
        //记录这次操作,用于撤销
        undoCommand = onCommands[no];
    }

    /**
     * 按下关按钮
     *
     * @param no 编号
     */
    public void offButtonPushed(int no) {
        //找到按下的开按钮,并调用相应方法
        offCommands[no].execute();
        //记录这次操作,用于撤销
        undoCommand = offCommands[no];
    }

    /**
     * 按撤销按钮
     */
    public void undoButtonPushed() {
        undoCommand.undo();
    }

}

测试类

package com.taoke.designPattern.command;

/**
 * 命令模式测试类
 *
 * @author taoke
 * @date 2022/7/22
 */
public class CommandTest {

    public static void main(String[] args) {
        //使用命令设计模式,使用遥控器对电灯进行控制
        //创建电灯的对象(接收者)
        LightReceiver receiver = new LightReceiver();
        //创建电灯相关的开关命令
        LightOnCommand onCommand = new LightOnCommand(receiver);
        LightOffCommand offCommand = new LightOffCommand(receiver);
        //创建一个控制器
        RemoteController controller = new RemoteController();
        //给控制器设置命令,比如 n = 0 是对灯进行开/关操作
        controller.setCommands(0, onCommand, offCommand);
        System.out.println("-------按下灯的开按钮-------");
        controller.onButtonPushed(0);
        System.out.println("-------按下灯的关按钮-------");
        controller.offButtonPushed(0);
        System.out.println("-------按下灯的撤销按钮-------");
        controller.undoButtonPushed();

        System.out.println("=============使用遥控器操作电视机==================");
        TVReceiver tvReceiver = new TVReceiver();
        //创建电视机相关的开关命令
        TVOnCommand tvOnCommand = new TVOnCommand(tvReceiver);
        TVOffCommand tvOffCommand = new TVOffCommand(tvReceiver);
        //给控制器设置命令,比如 n = 1 是对电视机进行开/关操作
        controller.setCommands(1, tvOnCommand, tvOffCommand);
        System.out.println("-------按下电视的开按钮-------");
        controller.onButtonPushed(1);
        System.out.println("-------按下电视的关按钮-------");
        controller.offButtonPushed(1);
        System.out.println("-------按下电视的撤销按钮-------");
        controller.undoButtonPushed();
    }

}

三、访问者模式

  • 访问者模式(Visitor Pattern ),封装一些作用域某种数据结构的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作
  • 主要将数据结构与数据操作分离,解决数据结构和操作耦合性问题
  • 访问者模式的基本工作原理是:在被访问的类里面加一个对外提供的接待访问者的接口
  • 访问者模式主要的应用场景是:需要对一个对象结构中的对象进行很多不同操作(这些操作彼此没有关联),同时需要避免让这些操作“污染”这些对象的类,可以选用访问者模式

访问者模式角色

Visitor:抽象访问者,为该对象结构中每个ConcreteElement类中申明一个visit操作

ConcreteVisitor:具体访问者,实现Visitor中申明的操作

ObjectStructure:对象结构,能枚举它的元素,提供一个高层的接口,允许访问者访问元素

Element:抽象元素,顶一个accept方法,接受一个访问者对象

ConcreteElement:具体元素,实现了accept方法

访问者模式UML图

 实例应用

         测评系统将人、观众分为男人和女人,对歌手进行测评,当看完某个歌手表演后,得到他们对该歌手不同的评价(评价有不同的种类,比如成功、失败等)

抽象访问者

package com.taoke.designPattern.visitor;

/**
 * 对参赛人员进行打分
 *
 * @author taoke
 * @date 2022/7/25
 */
public abstract class Action {

    /**
     * 得到男人的得分
     *
     * @param man 男人
     */
    public abstract void getManResult(Man man);

    /**
     * 得到女人的得分
     *
     * @param woman 女人
     */
    public abstract void getWoManResult(Woman woman);


}

具体访问者

package com.taoke.designPattern.visitor;

/**
 * 成功的评价
 *
 * @author taoke
 * @date 2022/7/25
 */
public class Success extends Action {

    @Override
    public void getManResult(Man man) {
        System.out.println("男人给的评价该歌手很成功!");
    }

    @Override
    public void getWoManResult(Woman woman) {
        System.out.println("女人给的评价该歌手很成功!");
    }

}

package com.taoke.designPattern.visitor;

/**
 * 失败的评价
 *
 * @author taoke
 * @date 2022/7/25
 */
public class Fail extends Action {

    @Override
    public void getManResult(Man man) {
        System.out.println("男人给的评价该歌手很失败!");
    }

    @Override
    public void getWoManResult(Woman woman) {
        System.out.println("女人给的评价该歌手很失败!");
    }

}

抽象元素

package com.taoke.designPattern.visitor;

/**
 * 人
 *
 * @author taoke
 * @date 2022/7/25
 */
public abstract class Person {

    /**
     * 提供一个方法,访问者可以访问
     *
     * @param action 动作
     */
    public abstract void accept(Action action);

}

具体元素

package com.taoke.designPattern.visitor;

/**
 * 男人
 *
 * @author taoke
 * @date 2022/7/25
 */
public class Man extends Person {

    /**
     * 这里使用了双分派,即首先在客户端程序中,将具体状态作为参数传递Woman中
     * 然后Woman类调用作为参数的 “具体方法” getWomanResult,同时将自己this作为参数传入,完成第二次分派
     *
     * @param action 动作
     */
    @Override
    public void accept(Action action) {
        action.getManResult(this);
    }

}
package com.taoke.designPattern.visitor;

/**
 * @author taoke
 * @date 2022/7/25
 */
public class Woman extends Person {

    @Override
    public void accept(Action action) {
        action.getWoManResult(this);
    }

}

对象结构

package com.taoke.designPattern.visitor;

import java.util.LinkedList;
import java.util.List;

/**
 * 数据结构,管理很多人
 *
 * @author taoke
 * @date 2022/7/25
 */
public class ObjectStructure {

    /**
     * 人的集合
     */
    private final List<Person> people = new LinkedList<>();

    /**
     * 添加到集合
     *
     * @param person 人
     */
    public void attach(Person person) {
        people.add(person);
    }

    /**
     * 从集合移除
     *
     * @param person 人
     */
    public void detach(Person person) {
        people.remove(person);
    }

    /**
     * 显示测评情况
     *
     * @param action 动作
     */
    public void display(Action action) {
        people.forEach(i -> i.accept(action));
    }


}

测试类

package com.taoke.designPattern.visitor;

/**
 * 访问者模式测试类
 *
 * @author taoke
 * @date 2022/7/25
 */
public class VisitorTest {

    public static void main(String[] args) {
        ObjectStructure structure = new ObjectStructure();
        structure.attach(new Man());
        structure.attach(new Woman());
        //成功
        structure.display(new Success());
        System.out.println("====================");
        //失败
        structure.display(new Fail());
    }


}

四、迭代器模式

        迭代器模式(Iterator Pattern),提供一种遍历集合的同一接口,用一致的方法遍历集合元素,不需要知道集合对象的底层表示,即不暴露内部的结构。如果我们的集合元素是用不同方式实现的,有数组,集合或者其他方式。当客户要遍历这些集合元素的时候就要使用多种遍历方式,而且还会暴露元素的内部结构,可以考虑使用迭代器模式解决。

迭代器模式角色

Iterator:迭代器接口,系统系统,含有hasNext,next,remove

ConcreteIterator:具体的迭代器,管理相关的迭代

Aggregate:聚合接口,将客户端和具体的聚合解耦

ConcreteAggregate:具体的聚合类,提供一个方法,返回可以正确遍历集合的迭代器

Client:客户端通过Iterator迭代器接口和Aggregate聚合接口依赖其具体的迭代器和聚合子类

迭代器模式UML图

应用实例

        展示一个学校院系结构,要在一个页面中展示出学校的院系组成,一个学校有多个学院,一个学院有多个系

具体迭代器

package com.taoke.designPattern.iterator;

import java.util.Iterator;

/**
 * 计算机学院迭代器
 *
 * @author taoke
 * @date 2022/7/26
 */
public class ComputerCollegeIterator implements Iterator<Department> {

    /**
     * 系的集合
     */
    private final Department[] departments;

    /**
     * 遍历的位置
     */
    private int position;

    public ComputerCollegeIterator(Department[] departments) {
        this.departments = departments;
    }

    @Override
    public boolean hasNext() {
        return position <= departments.length - 1;
    }

    @Override
    public Department next() {
        return departments[position++];
    }

}
package com.taoke.designPattern.iterator;

import java.util.Iterator;
import java.util.List;

/**
 * 信息学院迭代器
 *
 * @author taoke
 * @date 2022/7/26
 */
public class InfoCollegeIterator implements Iterator<Department> {

    private final List<Department> departmentList;

    private int index = 0;

    public InfoCollegeIterator(List<Department> departmentList) {
        this.departmentList = departmentList;
    }

    @Override
    public boolean hasNext() {
        return index <= departmentList.size() - 1;
    }

    @Override
    public Department next() {
        return departmentList.get(index++);
    }
}

聚合接口

package com.taoke.designPattern.iterator;

import java.util.Iterator;

/**
 * 学院
 *
 * @author taoke
 * @date 2022/7/26
 */
public interface College<E> {

    String getName();

    void addDepartment(String name, String desc);

    Iterator<E> createIterator();
}

具体聚合接口

package com.taoke.designPattern.iterator;

import java.util.Iterator;

/**
 * 计算机学院
 *
 * @author taoke
 * @date 2022/7/26
 */
public class ComputerCollege implements College<Department> {

    /**
     * 系集合
     */
    private final Department[] departments;

    /**
     * 系的个数
     */
    private int departmentSize = 0;

    public ComputerCollege() {
        departments = new Department[3];
        addDepartment("java", "java专业");
        addDepartment("c语言", "c语言专业");
        addDepartment("python", "python专业");
    }

    @Override
    public String getName() {
        return "计算机学院";
    }

    @Override
    public void addDepartment(String name, String desc) {
        departments[departmentSize++] = new Department(name, desc);
    }

    @Override
    public Iterator<Department> createIterator() {
        return new ComputerCollegeIterator(departments);
    }

}

package com.taoke.designPattern.iterator;

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

/**
 * 信息学院
 *
 * @author taoke
 * @date 2022/7/26
 */
public class InfoCollege implements College<Department> {

    private final List<Department> departmentList;

    public InfoCollege() {
        departmentList = new ArrayList<>();
        addDepartment("信息安全", "信息安全专业");
        addDepartment("网络安全", "网络安全专业");
    }

    @Override
    public String getName() {
        return "信息工程学院";
    }

    @Override
    public void addDepartment(String name, String desc) {
        departmentList.add(new Department(name, desc));
    }

    @Override
    public Iterator<Department> createIterator() {
        return new InfoCollegeIterator(departmentList);
    }
}

测试类

package com.taoke.designPattern.iterator;

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

/**
 * 迭代器模式测试类
 *
 * @author taoke
 * @date 2022/7/26
 */
public class IteratorTest {

    public static void main(String[] args) {
        //创建学院
        List<College<Department>> collegeList = new ArrayList<>();
        ComputerCollege computerCollege = new ComputerCollege();
        InfoCollege infoCollege = new InfoCollege();
        collegeList.add(computerCollege);
        collegeList.add(infoCollege);
        printCollege(collegeList);
    }


    /**
     * 打印所有的学院
     */
    private static void printCollege(List<College<Department>> list) {
        for (College<Department> college : list) {
            System.out.println(college.getName());
            printDepartment(college.createIterator());
        }
    }

    /**
     * 打印学院所有的系
     *
     * @param iterator 迭代器
     */
    private static void printDepartment(Iterator<Department> iterator) {
        while (iterator.hasNext()) {
            Department department = iterator.next();
            System.out.println(department.getName());
        }
    }
}

五、观察者模式

        对象之间多对一依赖的一种设计方案,被依赖的对象为Subject,依赖的对象为Observer,Subject通知Observer,比如气象站是Subject,是一的一方,用户是Observer,是多的一方

观察者模式角色

Subject:抽象主题角色,将所有观察者对象的引用保存在一个集合中,每个抽象主题角色都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者角色,一般用一个抽象类或者接口实现

ConceteSubject:具体主题角色,在具体主题内部状态改变时,给所有登记过的观察者发出通知,具体主题角色通常用一个子类实现

Observer:抽象观察者,为所有具体的观察者定义一个接口,在得到主题的通知时更新自己

ConcreteObserver:具体的观察者,该角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调,如果需要,具体观察者角色可以有一个指向具体的主题角色的引用,通常用一个子类实现

观察者模式UML图

应用实例

  • 气象站可以将每天测量到的温度,湿度,气压等等以公告的形式发布出去(比如发布到自己的网站或第三方)
  • 需要设计开放型 API,便于其他第三方也能接入气象站获取数据
  • 提供温度、气压和湿度的接口
  • 测量数据更新时,要能实时的通知给第三方

抽象主题

package com.taoke.designPattern.observer;

/**
 * 被观察者
 *
 * @author taoke
 * @date 2022/7/26
 */
public interface Subject {

    /**
     * 注册观察者
     *
     * @param observer 观察者
     */
    void registerObserver(Observer observer);

    /**
     * 移除观察者
     *
     * @param observer 观察者
     */
    void removeObserver(Observer observer);

    /**
     * 通知所有的观察者
     */
    void notifyObservers();
}

具体主题

package com.taoke.designPattern.observer;

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

/**
 * 1、包含最新的天气情况信息
 * 2、含有 观察者集合,使用Arraylist管理
 * 3、当数据有更新时,就主动调用Arraylist,通知所有的(接入方)就看到最新的信息
 *
 * @author taoke
 * @date 2022/7/26
 */
public class WeatherData implements Subject {

    /**
     * 温度
     */
    private float temperature;

    /**
     * 气压
     */
    private float pressure;

    /**
     * 湿度
     */
    private float humidity;

    /**
     * 观察者集合
     */
    private final List<Observer> observers;

    public WeatherData() {
        this.observers = new ArrayList<>();
    }

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

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

    public void setData(float temperature, float pressure, float humidity) {
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        notifyObservers();
    }

    @Override
    public void notifyObservers() {
        observers.forEach(i -> i.update(getTemperature(), getPressure(), getHumidity()));
    }

    public float getTemperature() {
        return temperature;
    }

    public float getPressure() {
        return pressure;
    }

    public float getHumidity() {
        return humidity;
    }
}

抽象观察者

package com.taoke.designPattern.observer;

/**
 * 观察者
 *
 * @author taoke
 * @date 2022/7/26
 */
public interface Observer {

    void update(float temperature, float pressure, float humidity);

}

具体观察者

package com.taoke.designPattern.observer;

/**
 * 新浪网站
 *
 * @author taoke
 * @date 2022/7/26
 */
public class SinaSite implements Observer {

    /**
     * 温度
     */
    private float temperature;

    /**
     * 气压
     */
    private float pressure;

    /**
     * 湿度
     */
    private float humidity;


    @Override
    public void update(float temperature, float pressure, float humidity) {
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        display();
    }

    public void display() {
        System.out.println("===========新浪网站===========");
        System.out.println("temperature=" + temperature);
        System.out.println("pressure=" + pressure);
        System.out.println("humidity=" + humidity);
    }
}
package com.taoke.designPattern.observer;

/**
 * 百度网站
 *
 * @author taoke
 * @date 2022/7/26
 */
public class BaiduSite implements Observer {

    /**
     * 温度
     */
    private float temperature;

    /**
     * 气压
     */
    private float pressure;

    /**
     * 湿度
     */
    private float humidity;

    @Override
    public void update(float temperature, float pressure, float humidity) {
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        display();
    }

    public void display() {
        System.out.println("===========百度网站===========");
        System.out.println("temperature=" + temperature);
        System.out.println("pressure=" + pressure);
        System.out.println("humidity=" + humidity);
    }
}

测试类

package com.taoke.designPattern.observer;

/**
 * 观察者模式测试类
 *
 * @author taoke
 * @date 2022/7/26
 */
public class ObserverTest {

    public static void main(String[] args) {
        //创建天气数据
        WeatherData weatherData = new WeatherData();
        //创建观察者
        BaiduSite baiduSite = new BaiduSite();
        SinaSite sinaSite = new SinaSite();
        //注册到weather
        weatherData.registerObserver(baiduSite);
        weatherData.registerObserver(sinaSite);

        System.out.println("*************通知所有的观察者**************");
        weatherData.setData(30f, 100f, 20.2f);

        System.out.println("*************移除新浪网站**************");
        weatherData.removeObserver(sinaSite);
        weatherData.setData(30f, 100f, 20.2f);
    }

}

六、中介者模式

        中介者模式(Mediator Pattern),用一个中介对象来封装一系列的对象交互,中介者使各个对象不需要显示的相互引用,从而使其耦合松散,而且可以独立的改变他们之间的交互。比如MVC模式,控制器controller 是模型Model和视图View的中介者,在前后端交互时起到了中间人的作用。

中介者模式的角色

Mediator:抽象中介者,定义了同事对象到中介者的接口

ConcreteMediator:具体的中介者对象,实现抽象中介者方法,需要知道所有具体的同事类,即以一个集合来管理HashMap,并接受某个同事对象消息,完成相应的任务

Colleague:抽象同事类

ConcreteColleague:具体同事类,会有很多,只知道自己的行为,而不了解其他同事类的行为(方法),但他们都依赖中介者对象

中介者模式UML图

应用实例

  • 智能家庭包括各种设备,闹钟、咖啡机、电视机、窗帘等
  • 主人要看电视时,各个设备可以协同工作,自动完成看电视的准备工作,比如流程为:
    闹铃响起 => 咖啡机开始做咖啡 => 窗帘自动落下 => 电视机开始播放

抽象中介者

package com.taoke.designPattern.mediator;

/**
 * 中介者
 *
 * @author taoke
 * @date 2022/7/26
 */
public abstract class Mediator {

    /**
     * 将中介者对象加入到集合中
     *
     * @param name      中介者名字
     * @param colleague 中介者
     */
    public abstract void register(String name, Colleague colleague);

    public abstract void getMessage(int state, String name);

    public abstract void sendMessage(int state);

}

具体中介者

package com.taoke.designPattern.mediator;

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

/**
 * 具体中介者
 *
 * @author taoke
 * @date 2022/7/26
 */
public class ConcreteMediator extends Mediator {

    private final Map<String, Colleague> colleagueMap;

    private final Map<String, String> interMap;

    public ConcreteMediator() {
        colleagueMap = new HashMap<>();
        interMap = new HashMap<>();
    }


    @Override
    public void register(String name, Colleague colleague) {
        colleagueMap.put(name, colleague);
        if (colleague instanceof Alarm) {
            interMap.put("Alarm", name);
        } else if (colleague instanceof CoffeeMachine) {
            interMap.put("CoffeeMachine", name);
        } else if (colleague instanceof TV) {
            interMap.put("TV", name);
        } else if (colleague instanceof Curtains) {
            interMap.put("Curtains", name);
        }
    }

    @Override
    public void getMessage(int state, String name) {
        //处理闹钟发出的消息
        if (colleagueMap.get(name) instanceof Alarm) {
            if (state == 0) {
                ((CoffeeMachine) (colleagueMap.get(interMap.get("CoffeeMachine")))).startCoffee();
                ((TV) (colleagueMap.get(interMap.get("TV")))).startTV();
            } else if (state == 1) {
                ((TV) (colleagueMap.get(interMap.get("TV")))).stopTV();
            }
        } else if (colleagueMap.get(name) instanceof CoffeeMachine) {
            ((Curtains) (colleagueMap.get(interMap.get("Curtains")))).upCurtains();
        }
    }

    @Override
    public void sendMessage(int state) {

    }
}

抽象同事类

package com.taoke.designPattern.mediator;

/**
 * 抽象同事类
 *
 * @author taoke
 * @date 2022/7/26
 */
public abstract class Colleague {

    private final String name;

    private final Mediator mediator;

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

    public Mediator getMediator() {
        return mediator;
    }

    public String getName() {
        return name;
    }

    public abstract void sendMessage(int state);
}

具体同事类

package com.taoke.designPattern.mediator;

/**
 * 闹钟
 *
 * @author taoke
 * @date 2022/7/26
 */
public class Alarm extends Colleague {

    public Alarm(String name, Mediator mediator) {
        super(name, mediator);
        mediator.register(name, this);
    }

    public void sendAlarm(int state) {
        sendMessage(state);
    }

    @Override
    public void sendMessage(int state) {
        getMediator().getMessage(state, getName());
    }

}
package com.taoke.designPattern.mediator;

/**
 * 咖啡机
 *
 * @author taoke
 * @date 2022/7/26
 */
public class CoffeeMachine extends Colleague {

    public CoffeeMachine(String name, Mediator mediator) {
        super(name, mediator);
        mediator.register(name, this);
    }

    @Override
    public void sendMessage(int state) {
        getMediator().getMessage(state, getName());
    }

    public void startCoffee() {
        System.out.println("startCoffee...");
    }

    public void finishCoffee() {
        System.out.println("After 5 minutes!");
        System.out.println("Coffee is ok!");
        sendMessage(0);
    }
}
package com.taoke.designPattern.mediator;

/**
 * 窗帘
 *
 * @author taoke
 * @date 2022/7/26
 */
public class Curtains extends Colleague {

    public Curtains(String name, Mediator mediator) {
        super(name, mediator);
        mediator.register(name, this);
    }

    @Override
    public void sendMessage(int state) {
        getMediator().getMessage(state, getName());
    }

    public void upCurtains() {
        System.out.println("up curtains");
    }
}

package com.taoke.designPattern.mediator;

/**
 * 电视
 *
 * @author taoke
 * @date 2022/7/26
 */
public class TV extends Colleague {

    public TV(String name, Mediator mediator) {
        super(name, mediator);
        mediator.register(name, this);
    }

    @Override
    public void sendMessage(int state) {
        getMediator().getMessage(state, getName());
    }

    public void startTV() {
        System.out.println("start tv");
    }

    public void stopTV() {
        System.out.println("stop tv");
    }
}

测试类

package com.taoke.designPattern.mediator;

/**
 * 中介者模式测试类
 *
 * @author taoke
 * @date 2022/7/26
 */
public class MediatorTest {

    public static void main(String[] args) {
        //创建一个中介者对象
        Mediator mediator = new ConcreteMediator();

        //创建Alarm 并且加入到  ConcreteMediator 对象的HashMap
        Alarm alarm = new Alarm("alarm", mediator);

        //创建了CoffeeMachine 对象,并  且加入到  ConcreteMediator 对象的HashMap
        CoffeeMachine coffeeMachine = new CoffeeMachine("coffeeMachine", mediator);

        //创建 Curtains , 并  且加入到  ConcreteMediator 对象的HashMap
        Curtains curtains = new Curtains("curtains", mediator);
        TV tv = new TV("TV", mediator);

        alarm.sendAlarm(0);
        coffeeMachine.finishCoffee();
        alarm.sendAlarm(1);
    }
}

七、备忘录模式

  • 备忘录模式(Memento Pattern):在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态
  • 可以这样理解备忘录模式:现实生活中的备忘录是用来记录某些要去做的事情,或者是记录已经达成的共同意见的事情,以防忘记了。而在软件层面,备忘录模式有着相同的含义,备忘录对象主要用来记录一个对象的某种状态,或者某些数据,当要做回退时,可以从备忘录对象里获取原来的数据进行恢复操作

备忘录模式的角色

  • Originator:源对象,需要保存的状态
  • Memento:备忘录对象,负责保存Originator内部状态
  • CareTaker:守护者对象,负责存放多个Memento对象,使用集合管理,提高效率

备忘录模式UML图

应用实例

        游戏鱼色有攻击力和防御力,在大战 Boss 前保存自身的状态(攻击力和防御力),当大战 Boss 后攻击力和防御万下降,从备忘录对象恢复到大战前的状态

源对象

package com.taoke.designPattern.memento;

/**
 * 游戏角色
 *
 * @author taoke
 * @date 2022/7/27
 */
public class GameRole {

    /**
     * 攻击力
     */
    private int vit;

    /**
     * 防御力
     */
    private int def;

    /**
     * 创建备忘录对象
     *
     * @return 备忘录对象
     */
    public Memento createMemento() {
        return new Memento(vit, def);
    }

    /**
     * 从备忘录中恢复
     *
     * @param memento 备忘录
     */
    public void recoverMemento(Memento memento) {
        this.vit = memento.getVit();
        def = memento.getDef();
    }

    public void display() {
        System.out.println(this);
    }

    public int getVit() {
        return vit;
    }

    public void setVit(int vit) {
        this.vit = vit;
    }

    public int getDef() {
        return def;
    }

    public void setDef(int def) {
        this.def = def;
    }

    @Override
    public String toString() {
        return "GameRole{" +
                "vit=" + vit +
                ", def=" + def +
                '}';
    }
}

备忘录对象

package com.taoke.designPattern.memento;

/**
 * 备忘录对象
 *
 * @author taoke
 * @date 2022/7/27
 */
public class Memento {

    /**
     * 攻击力
     */
    private int vit;

    /**
     * 防御力
     */
    private int def;

    public Memento(int vit, int def) {
        this.vit = vit;
        this.def = def;
    }

    public int getVit() {
        return vit;
    }

    public void setVit(int vit) {
        this.vit = vit;
    }

    public int getDef() {
        return def;
    }

    public void setDef(int def) {
        this.def = def;
    }
}

守护者对象

package com.taoke.designPattern.memento;

/**
 * 守护者对象,保存游戏的对象
 *
 * @author taoke
 * @date 2022/7/27
 */
public class Caretaker {

    /**
     * 备忘录对象
     */
    private Memento memento;

    public Memento getMemento() {
        return memento;
    }

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

测试类

package com.taoke.designPattern.memento;

/**
 * 备忘录模式测试类
 *
 * @author taoke
 * @date 2022/7/27
 */
public class MementoTest {

    public static void main(String[] args) {
        GameRole gameRole = new GameRole();
        gameRole.setDef(100);
        gameRole.setVit(100);
        System.out.println("====之前的状态====");
        gameRole.display();

        //把状态保存到caretaker
        Caretaker caretaker = new Caretaker();
        caretaker.setMemento(gameRole.createMemento());


        System.out.println("====之后的状态====");
        gameRole.setVit(30);
        gameRole.setDef(30);

        gameRole.display();

        System.out.println("====使用备忘录模式恢复到之前的状态====");

        gameRole.recoverMemento(caretaker.getMemento());
        gameRole.display();

    }

}

八、解释器模式

  • 在编译原理中,一个算术表达式通过词法分析器形成词法单元,而后这些词法单元再通过语法分析器构建语法分析树,最终形成一颗抽象的语法分析树。这里的词法分析器和语法分析器都可以看做是解释器
  • 解释器模式(Interpreter Pattern):是指给定一个语言(表达式),定义它的文法的一种表示,并定义一个解释器,使用该解释器来解释语言中的句子(表达式)
  • 应用场景:应用可以将一个需要解释执行的语言中的句子表示为一个抽象语法树,一些重复出现的问题可以用一种简单的语言来表达,一个简单语法需要解释的场景
  • 这样的例子还有,比如编译器、运算表达式计算、正则表达式、机器人等

解释器模式的角色

Context:环境角色,含有解释器之外的全局信息

AbstractExpression:抽象表达式,声明一个抽象的解释器操作,该方法为抽象语法树中所有节点共享

TerminalExpression:终结符表达式,实现与文法中终结符相关的解释操作

NonTerminalExpression:非终结符表达式,实现与文法中非终结符相关的解释操作

解释器模式UML图

实例应用

通过解释器模式来实现四则运算,如计算a + b - c的值,具体要求

  • 先输入表达式的形式,比如a + b + c - d + e,要求表达式的字母不能重复
  • 在分别输入a, b, c, d, e的值

抽象表达式

package com.taoke.designPattern.interpreter;

import java.util.Map;

/**
 * 解释器
 *
 * @author taoke
 * @date 2022/7/27
 */
public abstract class Expression {

    /**
     * 解释公式和数值, key 就是公式(表达式) 参数[a,b,c], value就是就是具体值
     * HashMap {a=10, b=20}
     *
     * @param var 变量
     * @return 结果
     */
    public abstract int interpreter(Map<String, Integer> var);
}

非终结符表达式

package com.taoke.designPattern.interpreter;

import java.util.Map;

/**
 * 抽象运算符号解析器 这里,每个运算符号,都只和自己左右两个数字有关系,
 * 但左右两个数字有可能也是一个解析的结果,无论何种类型,都是Expression类的实现类
 *
 * @author taoke
 * @date 2022/7/27
 */
public class SymbolExpression extends Expression {

    protected Expression left;
    protected Expression right;

    public SymbolExpression(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }

    /**
     * 因为 SymbolExpression 是让其子类来实现,因此 interpreter 是一个默认实现
     *
     * @param var 变量
     * @return 值
     */
    @Override
    public int interpreter(Map<String, Integer> var) {
        return 0;
    }
}
package com.taoke.designPattern.interpreter;

import java.util.Map;

/**
 * 加法解释器
 *
 * @author taoke
 * @date 2022/7/27
 */
public class AddExpression extends SymbolExpression {

    public AddExpression(Expression left, Expression right) {
        super(left, right);
    }

    /**
     * 处理相加
     *
     * @param var 变量
     * @return 结果
     */
    public int interpreter(Map<String, Integer> var) {
        //super.left.interpreter(var) : 返回 left 表达式对应的值 a = 10
        //super.right.interpreter(var): 返回right 表达式对应值 b = 20
        return super.left.interpreter(var) + super.right.interpreter(var);
    }
}

package com.taoke.designPattern.interpreter;

import java.util.Map;

/**
 * 减法解释器
 *
 * @author taoke
 * @date 2022/7/27
 */
public class SubExpression extends SymbolExpression {

    public SubExpression(Expression left, Expression right) {
        super(left, right);
    }

    /**
     * 求出left 和 right 表达式相减后的结果
     *
     * @param var 变量
     * @return 值
     */
    public int interpreter(Map<String, Integer> var) {
        return super.left.interpreter(var) - super.right.interpreter(var);
    }
}

环境角色

package com.taoke.designPattern.interpreter;

import java.util.Map;
import java.util.Stack;

public class Calculator {

    /**
     * 定义表达式
     */
    private final Expression expression;

    /**
     * 构造函数传参,并解析
     *
     * @param expStr 字符串表达式
     */
    public Calculator(String expStr) {
        // 安排运算先后顺序
        Stack<Expression> stack = new Stack<>();
        //表达式拆分成字符数组  [a, +, b]
        char[] charArray = expStr.toCharArray();

        Expression left;
        Expression right;
        //遍历我们的字符数组, 即遍历  [a, +, b]
        //针对不同的情况,做处理
        for (int i = 0; i < charArray.length; i++) {
            switch (charArray[i]) {
                case '+':
                    //从stack取出left => "a"
                    left = stack.pop();
                    // 取出右表达式 "b"
                    right = new VarExpression(String.valueOf(charArray[++i]));
                    // 然后根据得到left 和 right 构建 AddExpression加入stack
                    stack.push(new AddExpression(left, right));
                    break;
                case '-':
                    left = stack.pop();
                    right = new VarExpression(String.valueOf(charArray[++i]));
                    stack.push(new SubExpression(left, right));
                    break;
                default:
                    //如果是一个 Var 就创建要给 VarExpression 对象,并push到 stack
                    stack.push(new VarExpression(String.valueOf(charArray[i])));
                    break;
            }
        }
        //当遍历完整个 charArray 数组后,stack 就得到最后Expression
        this.expression = stack.pop();
    }

    public int run(Map<String, Integer> var) {
        //最后将表达式a+b和 var = {a=10,b=20}
        //然后传递给expression的interpreter进行解释执行
        return this.expression.interpreter(var);
    }
}

测试类

package com.taoke.designPattern.interpreter;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

/**
 * 解释器模式测试类
 *
 * @author taoke
 * @date 2022/7/27
 */
public class InterpreterTest {

    public static void main(String[] args) throws IOException {
        // a+b
        String expStr = getExpStr();
        // var {a=10, b=20}
        Map<String, Integer> var = getValue(expStr);
        Calculator calculator = new Calculator(expStr);
        System.out.println("运算结果:" + expStr + "=" + calculator.run(var));
    }

    /**
     * 获得表达式
     *
     * @return 表达式
     * @throws IOException 异常
     */
    public static String getExpStr() throws IOException {
        System.out.print("请输入表达式:");
        return (new BufferedReader(new InputStreamReader(System.in))).readLine();
    }

    /**
     * 获得值映射
     *
     * @param expStr 表达式
     * @return 值
     * @throws IOException 异常
     */
    public static Map<String, Integer> getValue(String expStr) throws IOException {
        Map<String, Integer> map = new HashMap<>();

        for (char ch : expStr.toCharArray()) {
            if (ch != '+' && ch != '-') {
                if (!map.containsKey(String.valueOf(ch))) {
                    System.out.print("请输入" + ch + "的值:");
                    String in = (new BufferedReader(new InputStreamReader(System.in))).readLine();
                    map.put(String.valueOf(ch), Integer.valueOf(in));
                }
            }
        }
        return map;
    }
}

九、状态模式

  • 状态模式(State Pattern):它主要用来解决对象在多种状态转换时,需要对外输出不同的行为的问题。状态和行为是一一对应的,状态之间可以相互转换
  • 当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像是改变了其类

状态模式角色

Context:环境角色,维护一个State实例,这个实例定义了当前状态

State:抽象状态角色,定义一个接口,封装与Context的一个特点接口相关行为

ConcreteState:具体状态角色,实现一个与Context的一个状态相关行为

状态模式UML图

应用实例 

APP 抽奖活动具体要求如下:

  • 假如每参加一次这个活动要扣除用户 50 积分,中奖概率是 10%
  • 奖品数量固定,抽完就不能抽奖
  • 活动有四个状态:可以抽奖、不能抽奖、发放奖品和奖品领完

抽象状态

package com.taoke.designPattern.state;

/**
 * 状态抽象类
 *
 * @author taoke
 * @date 2022/7/28
 */
public abstract class State {

    /**
     * 扣除积分
     */
    public abstract void deduceMoney();

    /**
     * 抽奖
     *
     * @return 抽奖结果
     */
    public abstract boolean raffle();

    /**
     * 发放奖品
     */
    public abstract void dispensePrize();

}

具体状态角色

package com.taoke.designPattern.state;

import java.util.Random;

/**
 * 可以抽奖的状态
 *
 * @author taoke
 * @date 2022/7/28
 */
public class CanRaffleState extends State {

    private final RaffleActivity activity;

    public CanRaffleState(RaffleActivity activity) {
        this.activity = activity;
    }

    @Override
    public void deduceMoney() {
        System.out.println("已经扣取过了积分");
    }

    @Override
    public boolean raffle() {
        System.out.println("正在抽奖,请稍等!");
        Random r = new Random();
        int num = r.nextInt(10);
        // 10%中奖机会
        if (num == 0) {
            // 改变活动状态为发放奖品 context
            activity.setState(activity.getDispenseState());
            return true;
        } else {
            System.out.println("很遗憾没有抽中奖品!");
            // 改变状态为不能抽奖
            activity.setState(activity.getNoRaffleState());
            return false;
        }
    }

    @Override
    public void dispensePrize() {
        System.out.println("没中奖,不能发放奖品");
    }

}

package com.taoke.designPattern.state;

/**
 * 不能抽奖的状态
 *
 * @author taoke
 * @date 2022/7/28
 */
public class NoRaffleState extends State {

    private final RaffleActivity activity;

    public NoRaffleState(RaffleActivity activity) {
        this.activity = activity;
    }

    /**
     * 当前状态可以扣积分 , 扣除后,将状态设置成可以抽奖状态
     */
    @Override
    public void deduceMoney() {
        if (activity.getCount() > 0) {
            System.out.println("扣除50积分成功,您可以抽奖了");
            activity.setState(activity.getCanRaffleState());
        } else {
            activity.setState(activity.getDispenseOutState());
        }
    }

    @Override
    public boolean raffle() {
        System.out.println("扣了积分才能抽奖喔!");
        return false;
    }

    @Override
    public void dispensePrize() {
        System.out.println("不能发放奖品");
    }

}

package com.taoke.designPattern.state;

/**
 * 奖品发放的状态
 *
 * @author taoke
 * @date 2022/7/28
 */
public class DispenseState extends State {

    private final RaffleActivity activity;

    public DispenseState(RaffleActivity activity) {
        this.activity = activity;
    }

    @Override
    public void deduceMoney() {
        System.out.println("不能扣除积分");
    }

    @Override
    public boolean raffle() {
        System.out.println("不能抽奖");
        return false;
    }

    @Override
    public void dispensePrize() {
        if (activity.getCount() > 0) {
            System.out.println("恭喜中奖了");
            // 改变状态为不能抽奖
            activity.setState(activity.getNoRaffleState());
            //发放奖品
            activity.setCount(activity.getCount() - 1);
        } else {
            System.out.println("很遗憾,奖品发送完了");
            // 改变状态为奖品发送完毕, 后面我们就不可以抽奖
            activity.setState(activity.getDispenseOutState());
        }
    }

}
package com.taoke.designPattern.state;

/**
 * 奖品发放完毕的状态
 *
 * @author taoke
 * @date 2022/7/28
 */
public class DispenseOutState extends State {

    @Override
    public void deduceMoney() {
        System.out.println("奖品发送完了,请下次再参加");
    }

    @Override
    public boolean raffle() {
        System.out.println("奖品发送完了,请下次再参加");
        return false;
    }

    @Override
    public void dispensePrize() {
        System.out.println("奖品发送完了,请下次再参加");
    }

}

测试类

package com.taoke.designPattern.state;

/**
 * 状态模式测试类
 *
 * @author taoke
 * @date 2022/7/28
 */
public class StateTest {

    public static void main(String[] args) {
        // 创建活动对象,奖品有1个奖品
        RaffleActivity activity = new RaffleActivity(1);
        // 我们连续抽20次奖
        for (int i = 0; i < 20; i++) {
            System.out.println("--------第" + (i + 1) + "次抽奖----------");
            // 参加抽奖,第一步点击扣除积分
            activity.deduceMoney();
            // 第二步抽奖
            activity.raffle();
        }
    }
}

十、策略模式

        策略模式(Strategy Pattern)中,定义算法族,分别封装起来,让他们之间可以互相替换。此模式让算法的变化独立于使用算法的客户

策略模式角色

Strategy:抽象策略角色,给出所有具体策略所需的接口,所有具体的策略类都要实现这个接口

ConcreteStrategy:具体策略角色,实现了抽象策略定义的接口,提供具体的算法实现或行为

Context:环境角色,用于配置一个具体的算法策略角色,维持一个策略接口类型的引用,并且可以定义一个让接口Strategy的具体访问的接口

策略模式UML图

应用实例 

鸭子项目,具体要求如下:

  • 有各鸭子(比如野鸭、北京鸭、水鸭等,鸭子有各种行为,比如叫、飞行等)
  • 显示鸭子的信息

UML图

抽象鸭子

package com.taoke.designPattern.strategy;

/**
 * 抽象类 鸭子
 *
 * @author taoke
 * @date 2022/7/28
 */
public abstract class Duck {

    public Duck() {
    }

    /**
     * 飞行属性
     */
    protected FlyBehavior flyBehavior;

    /**
     * 游泳属性
     */
    protected SwimBehavior swimBehavior;

    /**
     * 展示鸭子信息
     */
    public abstract void display();

    public void swim() {
        if (swimBehavior != null) {
            swimBehavior.swim();
        }
    }

    public void fly() {
        if (flyBehavior != null) {
            flyBehavior.fly();
        }
    }

    public void setFlyBehavior(FlyBehavior flyBehavior) {
        this.flyBehavior = flyBehavior;
    }

    public void setSwimBehavior(SwimBehavior swimBehavior) {
        this.swimBehavior = swimBehavior;
    }
}

具体鸭子

package com.taoke.designPattern.strategy;

/**
 * 玩具鸭
 *
 * @author taoke
 * @date 2022/7/28
 */
public class ToyDuck extends Duck {

    public ToyDuck() {
        flyBehavior = new NoFlyBehavior();
    }

    @Override
    public void display() {
        System.out.println("我是玩具鸭~~~");
    }

}
package com.taoke.designPattern.strategy;

/**
 * 野鸭子
 *
 * @author taoke
 * @date 2022/7/28
 */
public class WildDuck extends Duck {

    public WildDuck() {
        flyBehavior = new GoodFlyBehavior();
    }

    @Override
    public void display() {
        System.out.println("我是野鸭~~~");
    }

}
package com.taoke.designPattern.strategy;

/**
 * 北京鸭
 *
 * @author taoke
 * @date 2022/7/28
 */
public class PekingDuck extends Duck {

    public PekingDuck() {
        flyBehavior = new BadFlyBehavior();
    }

    @Override
    public void display() {
        System.out.println("我是北京鸭~~~");
    }

}

飞行行为

package com.taoke.designPattern.strategy;

/**
 * 飞行属性
 *
 * @author taoke
 * @date 2022/7/28
 */
public interface FlyBehavior {

    void fly();

}

具体飞行行为

package com.taoke.designPattern.strategy;

/**
 * 不会飞行
 *
 * @author taoke
 * @date 2022/7/28
 */
public class NoFlyBehavior implements FlyBehavior {

    @Override
    public void fly() {
        System.out.println("不会飞行~~~");
    }

}
package com.taoke.designPattern.strategy;

/**
 * 飞行技术不好
 *
 * @author taoke
 * @date 2022/7/28
 */
public class BadFlyBehavior implements FlyBehavior {

    @Override
    public void fly() {
        System.out.println("飞行技术很差~~~");
    }

}
package com.taoke.designPattern.strategy;

/**
 * 飞行技术好
 *
 * @author taoke
 * @date 2022/7/28
 */
public class GoodFlyBehavior implements FlyBehavior {

    @Override
    public void fly() {
        System.out.println("飞行技术高超~~~");
    }

}

游泳行为

package com.taoke.designPattern.strategy;

/**
 * 游泳属性
 *
 * @author taoke
 * @date 2022/7/28
 */
public interface SwimBehavior {

    void swim();

}

测试类

package com.taoke.designPattern.strategy;

/**
 * 策略模式测试类
 *
 * @author taoke
 * @date 2022/7/28
 */
public class StrategyTest {

    public static void main(String[] args) {
        WildDuck wildDuck = new WildDuck();
        wildDuck.display();
        wildDuck.fly();

        System.out.println("================");
        ToyDuck toyDuck = new ToyDuck();
        toyDuck.display();
        toyDuck.fly();

        System.out.println("================");
        PekingDuck pekingDuck = new PekingDuck();
        pekingDuck.display();
        pekingDuck.fly();

        System.out.println("================");
        //动态改变某个对象的行为, 北京鸭 不能飞
        pekingDuck.setFlyBehavior(new NoFlyBehavior());
        System.out.println("北京鸭的实际飞翔能力");
        pekingDuck.fly();
    }

}

十一、责任链模式

  • 职责链模式(Chain of Responsibility Pattern),又叫责任链模式:为请求创建了一个接收者对象的链。这种模式对请求的发送者和接收者进行解耦
  • 职责链模式通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推

责任链模式角色

Handler:抽象处理者,定义了一个处理请求的方法,同事含有一个Handler

ConcreteHandler:具体处理者,处理自己负责的请求,同事可以访问它的后继者(即下一个处理者),如果可以处理请求,则处理请求,否则交给后继者去处理,从而形成一个职责链

Request:含有很多属性,表示一个请求

责任链模式UML图

应用实例

学校 OA 系统的采购审批项目,需求是

  • 采购员采购教学器材
  • 如果金额小于等于 5000,由教学主任审批(0 < x ≤ 5000)
  • 如果金额小于等于 10000,由院长审批(5000 < x ≤ 10000)
  • 如果金额小于等于 30000,由副校长审批(10000< x ≤ 30000)
  • 如果金额超过 30000 以上,有校长审批(30000  < x)

抽象处理者

package com.taoke.designPattern.responsibility;

/**
 * 抽象审批者
 *
 * @author taoke
 * @date 2022/7/28
 */
public abstract class Approver {

    /**
     * 审批者
     */
    protected Approver approver;

    /**
     * 审批者名字
     */
    protected String name;

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

    /**
     * 设置下一个审批者
     *
     * @param approver 审批者
     */
    public void setApprover(Approver approver) {
        this.approver = approver;
    }

    /**
     * 处理审批请求的方法,得到一个请求, 处理是子类完成,因此该方法做成抽象
     *
     * @param purchaseRequest 请求类
     */
    public abstract void processRequest(PurchaseRequest purchaseRequest);
}

具体处理者

package com.taoke.designPattern.responsibility;

/**
 * 系审批人
 *
 * @author taoke
 * @date 2022/7/28
 */
public class DepartmentApprover extends Approver {

    public DepartmentApprover(String name) {
        super(name);
    }

    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        if (purchaseRequest.getPrice() <= 5000) {
            System.out.println(" 请求编号 id= " + purchaseRequest.getId() + " 被 " + this.name + " 处理");
        } else {
            approver.processRequest(purchaseRequest);
        }
    }
}
package com.taoke.designPattern.responsibility;

/**
 * 学院审批人
 *
 * @author taoke
 * @date 2022/7/28
 */
public class CollegeApprover extends Approver {

    public CollegeApprover(String name) {
        super(name);
    }

    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        if (purchaseRequest.getPrice() > 5000 && purchaseRequest.getPrice() <= 10000) {
            System.out.println(" 请求编号 id= " + purchaseRequest.getId() + " 被 " + this.name + " 处理");
        } else {
            approver.processRequest(purchaseRequest);
        }
    }
}

package com.taoke.designPattern.responsibility;

/**
 * 副校长审批人
 *
 * @author taoke
 * @date 2022/7/28
 */
public class ViceSchoolMasterApprover extends Approver {

    public ViceSchoolMasterApprover(String name) {
        super(name);
    }

    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        if (purchaseRequest.getPrice() > 10000 && purchaseRequest.getPrice() <= 30000) {
            System.out.println(" 请求编号 id= " + purchaseRequest.getId() + " 被 " + this.name + " 处理");
        } else {
            approver.processRequest(purchaseRequest);
        }
    }
}

package com.taoke.designPattern.responsibility;

/**
 * 校长审批人
 *
 * @author taoke
 * @date 2022/7/28
 */
public class SchoolMasterApprover extends Approver {

    public SchoolMasterApprover(String name) {
        super(name);
    }

    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        if (purchaseRequest.getPrice() > 30000) {
            System.out.println(" 请求编号 id= " + purchaseRequest.getId() + " 被 " + this.name + " 处理");
        } else {
            approver.processRequest(purchaseRequest);
        }
    }
}

请求类

package com.taoke.designPattern.responsibility;

/**
 * 请求类
 *
 * @author taoke
 * @date 2022/7/28
 */
public class PurchaseRequest {
    /**
     * 请求类型
     */
    private final int type;
    /**
     * 请求金额
     */
    private final float price;
    /**
     * 请求id
     */
    private final int id;

    public PurchaseRequest(int type, float price, int id) {
        this.type = type;
        this.price = price;
        this.id = id;
    }

    public int getType() {
        return type;
    }

    public float getPrice() {
        return price;
    }

    public int getId() {
        return id;
    }

}

测试类

package com.taoke.designPattern.responsibility;

/**
 * 责任链模式测试类
 *
 * @author taoke
 * @date 2022/7/28
 */
public class ResponsibilityTest {

    public static void main(String[] args) {
        PurchaseRequest purchaseRequest = new PurchaseRequest(1, 2000, 1);

        //创建相关的审批人
        Approver departmentApprover = new DepartmentApprover("张主任");
        Approver collegeApprover = new CollegeApprover("李院长");
        Approver viceSchoolMasterApprover = new ViceSchoolMasterApprover("王副校");
        Approver schoolMasterApprover = new SchoolMasterApprover("佟校长");

        //需要将各个审批级别的下一个设置好 (处理人构成环形: )
        departmentApprover.setApprover(collegeApprover);
        collegeApprover.setApprover(viceSchoolMasterApprover);
        viceSchoolMasterApprover.setApprover(schoolMasterApprover);
        schoolMasterApprover.setApprover(departmentApprover);

        departmentApprover.processRequest(purchaseRequest);
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值