设计模式3(行为型)

行为型模式

设计模式1(创建型)
设计模式2(结构型)
模板方法模式
命令模式
访问者模式
迭代器模式
观察者模式
中介者模式
备忘录模式
解释器模式
状态模式
策略模式
责任链模式

模板模式

模板模式(Template Pattern)使用有个抽象类公开定义它的方法模板;其子类根据自身需求可重写抽象方法。

模板模式相当于设定好了一个框架流程,子类作为具体实现,按照这个流程进行实现。对于相同的步骤可以使用具体的方法,而对于有差异的方法由子类具体实现。

优点:行为由父类控制、子类实现;提取了公共代码便于维护。

如下:

  • 需求:画图形,有圆形和矩形。

  • AbsShape:抽象模板类,定义了画图形的模板方法,只有draw()方法根据每个形状的不同二具体实现;

  • Circle、Rectangle:抽象类的子类,重写了draw()方法以适应个自的图形;

    Client:创建对象,执行画图形的操作。

在这里插入图片描述

AbsShape:

/**
 * 抽象类模板
 */
public abstract class AbsShape {
    // 画图形完整过程
    public void drawShape(){
        prepare();
        draw();
        fill();
        done();
    }
    // 准备
    public void prepare(){
        System.out.println("prepare draw shape tools");
    }
    // 画具体图像,不确定,使用抽象方法
    public abstract void draw();
    // 填色
    public void fill(){
        System.out.println("fill color");
    }
    // 完成
    public void done(){
        System.out.println("draw shape down");
    }
}

Circle:

/**
 * 画圆
 */
public class Circle extends AbsShape{
    @Override
    public void draw() {
        System.out.println("draw a circle");
    }
}

Rectangle:

/**
 * 画矩形
 */
public class Rectangle extends AbsShape{
    @Override
    public void draw() {
        System.out.println("draw a rectangle");
    }
}

Client:

public class Client {
    public static void main(String[] args) {
        // 画圆
        AbsShape circle = new Circle();
        circle.drawShape();
        /**
         * prepare draw shape tools
         * draw a circle
         * fill color
         * draw shape down
         */

        // 画矩形
        AbsShape rectangle = new Rectangle();
        rectangle.drawShape();
        /**
         * prepare draw shape tools
         * draw a rectangle
         * fill color
         * draw shape down
         */
    }
}

钩子方法

当对于一个子类不需要某一个方法时,使用钩子方法实现。改造如下:

1.添加钩子方法,并对需要的方法进行判断;

/**
 * 抽象类模板
 */
public abstract class AbsShape {
    // 画图形完整过程
    public void drawShape(){
        prepare();
        draw();
        // 根据钩子方法判断是否执行
        if(isUse()){
            fill();
        }
        done();
    }
    // 准备
    public void prepare(){
        System.out.println("prepare draw shape tools");
    }
    // 画具体图像,不确定,使用抽象方法
    public abstract void draw();
    // 填色
    public void fill(){
        System.out.println("fill color");
    }
    // 完成
    public void done(){
        System.out.println("draw shape down");
    }

    // 钩子方法
    boolean isUse(){
        return true;
    }
}

2.子类对钩子方法重写;

/**
 * 画圆
 */
public class Circle extends AbsShape{
    @Override
    public void draw() {
        System.out.println("draw a circle");
    }
	// 返回false就会使既定方法不执行
    @Override
    boolean isUse() {
        return false;
    }
}

具体使用

在Spring的IOC中有具体的应用:ConfigurableApplication接口中定义抽象方法;其实现类是一个抽象类,实现该方法并定义了初始化的步骤(具体方法或抽象方法),抽象类的子类再根据需求实现或重写方法。

命令模式

命令模式(Command pattern)是对请求的封装,将请求分装成一个对象,使得对于不同的请求参数化。请求以命令的形式包裹再对象中,并传给掉调用对象。

模式中的角色:

  • Command:命令接口,统一管理具有类似操作的命令;
  • ConcreteCommand:命令的具体实现,聚合了命令的执行者(Receiver),调用Receiver的方法执行命令;
  • Receiver:命令的执行者,接收者;
  • invoker:命令对象的传入地点,通过该类将命令与请求结合起来给客户端调用。

优点:降低系统的耦合程度;便于添加新的命令,无需修改代码,只需要添加Command的实现类即可。

如下:

  • 需求:对于数据库的事务操作,有提交(commit)、回滚(rollback),要使添加新的命令方便;
  • SqlCommand:数据库操作命令接口,定义了抽象方法commit、rollback;
  • DeleteCommand、UpdateCommand、InsertCommand:命令接口的实现类;
  • DatabaseReceiver:命令的接收者,也是实际的操作者;
  • Broker:方法的调用者,根据用户的命令,调用具体的方法;
  • Client:客户端,用户根据需要传入相应的命令对象以执行。

在这里插入图片描述

SqlCommand:

/**
 * sql操作命令
 */
public interface SqlCommand {
    // 提交
    void commit();
    // 回滚
    void rollback();
}

SqlCommand:

/**
 * 插入操作命令
 */
public class InsertCommand implements SqlCommand{
    // 聚合数据库操作类(命令执行者)
    private DatabaseReceiver receiver;
    public InsertCommand(DatabaseReceiver receiver) {
        this.receiver = receiver;
    }
    //  // 实现事务提交操作(插入)
    @Override
    public void commit() {
        receiver.insert();
    }
    // 回滚命令
    @Override
    public void rollback() {
        receiver.rollback();
    }
}

UpdateCommand:

/**
 * 更新命令
 */
public class UpdateCommand implements SqlCommand{
    // 聚合数据库操作类(命令执行者)
    private DatabaseReceiver receiver;
    public UpdateCommand(DatabaseReceiver receiver) {
        this.receiver = receiver;
    }
    // 实现事务提交操作(更新)
    @Override
    public void commit() {
        receiver.update();
    }

    @Override
    public void rollback() {
        receiver.rollback();
    }
}

DeleteCommand:

/**
 * 删除命令
 */
public class DeleteCommand implements SqlCommand{
    // 聚合数据库操作对象(命令执行者)
    private DatabaseReceiver receiver;
    public DeleteCommand(DatabaseReceiver receiver) {
        this.receiver = receiver;
    }
    // 实现事务提交操作(删除)
    @Override
    public void commit() {
        receiver.delete();
    }

    @Override
    public void rollback() {
        receiver.rollback();
    }
}

DatabaseReceiver:

/**
 * 数据库操作
 */
public class DatabaseReceiver {
    public void insert(){
        System.out.println("插入数据~");

    }
    public void update(){
        System.out.println("更新数据~");
    }
    public void delete(){
        System.out.println("删除数据~");
    }
    public void rollback(){
        System.out.println("回滚,操作无效~");
    }
}

Broker:

/**
 * invoker类,用于调用命令
 */
public class Broker {
    // 保存执行的命令
    private List<SqlCommand> sql = new ArrayList<>();
    // 调用并执行命令
    public void executeCommand(SqlCommand command){
        // 添加命令
        sql.add(command);
        // 执行
        command.commit();
    }
    // 对事务回滚
    public void undoCommand(SqlCommand command){
        // 如果没有进行过对应的操作,回滚失败
        if (!sql.contains(command)){
            System.out.println("事务未提交无法回滚");
            return;
        }
        command.rollback();
        sql.remove(command);
    }
}

Client:

public class Client {
    public static void main(String[] args) {
        // 创建数据库操作执行类
        DatabaseReceiver databaseReceiver = new DatabaseReceiver();
        // 操作命令
        InsertCommand insert = new InsertCommand(databaseReceiver);
        UpdateCommand update = new UpdateCommand(databaseReceiver);
        DeleteCommand delete = new DeleteCommand(databaseReceiver);
        // 创建命令调用类
        Broker broker = new Broker();
        // 1.插入操作
        broker.executeCommand(insert);
        // 2.插入错误,回滚
        broker.undoCommand(insert);
        // 3.更新操作
        broker.executeCommand(update);
        // 4.执行回滚删除操作
        broker.undoCommand(delete);
        /**
         * output:
         * 插入数据~
         * 回滚,操作无效~
         * 更新数据~
         * 事务未提交无法回滚
         */
    }
}

访问者模式

访问者模式(Visitor Patter)使用一个访问者类改变对实体类的执行算法。也就是对实体类的执行操作由访问者类来控制。

实现过程为:

  1. 客户端通过访问者类(visitor)访问元素——创建访问者对象,并将其传递元素;
  2. 元素接收访问之后再交由访问者操作——元素调用accept(Visitor v)方法接收访问者,并调用访问者的方法。

主要实现功能:将数据结构与数据操作分离。

优点:灵活、扩展性高。

缺点:依赖了实体类(见下面代码中的visitor类中的方法),违反了依赖倒置原则;实体类更变困难。

如下:

  • 需求:一个家庭有4个人(father、mather、son、daughter);现有一个访问者访问这个家庭各个成员;各成员接受访问之后访问者得到信息;最后右访问者将家庭的成员信息展示出来。
  • Person:家庭成员抽象类,有抽象放啊accept(),表示接收访问者访问;
  • Father、Mather、Son、Daughter:家庭的具体成员,实现方法并调用访问者的访问方法访问自己;
  • FamaryVisitor:访问者接口,定义访问家庭成员的方法,通过该方法展示该家庭的成员信息;
  • ConcreteFamilyVisitor:具体访问者,具有具体的访问方法;
  • Family:该类封装了访问者对该家庭的访问流程(也即访问者模式中的算法);
  • Client:创建访问者,开始访问并展示信息

在这里插入图片描述

Person:

public abstract class Person {
    // 接受访问的抽象方法,有子类实现
    public abstract void accept(FamilyVisitor familyVisitor);
}

Father:

public class Father extends Person 
    // 实现接受访问的方法,并调用访问者方法访问该对象,下同
    @Override
    public void accept(FamilyVisitor familyVisitor) {
        familyVisitor.visit(this);
    }
}

Mather:

public class Mather extends Person{
    @Override
    public void accept(FamilyVisitor familyVisitor) {
        familyVisitor.visit(this);
    }
}

Son:

public class Son extends Person{
    @Override
    public void accept(FamilyVisitor familyVisitor) {
        familyVisitor.visit(this);
    }
}

Daughter:

public class Daughter extends Person {
    @Override
    public void accept(FamilyVisitor familyVisitor) {
        familyVisitor.visit(this);
    }
}

FamilyVisitor:

public interface FamilyVisitor {
    // 访问家庭成员的额抽象方法
    void visit(Father father);
    void visit(Mather mather);
    void visit(Son son);
    void visit(Daughter daughter);
}

ConcreteFamilyVisitor:

public class ConcreteFamilyVisitor implements FamilyVisitor {
    // 对家庭成员的各个访问方法,这里可以看到使用的是具体的类而不是抽象类
    @Override
    public void visit(Father father) {
        System.out.println("visit father");
    }

    @Override
    public void visit(Mather mather) {
        System.out.println("visit mather");
    }

    @Override
    public void visit(Son son) {
        System.out.println("visit son");
    }

    @Override
    public void visit(Daughter daughter) {
        System.out.println("visit daughter");
    }
}

Family:

public class Family {
    // 成员集合
    private List<Person> list;
	// 成员初始化
    public Family() {
        this.list = Arrays.asList(new Father(), new Mather(), new Son(), new Daughter());
    }
	// 具体的算法,这里表示逐个访问
    public void display(FamilyVisitor visitor){
        for(Person p : list){
            p.accept(visitor);
        }
    }
}

Client:

public class Client {
    public static void main(String[] args) {
        Family family = new Family();
        ConcreteFamilyVisitor visitor = new ConcreteFamilyVisitor();
        family.display(visitor);
    }
}

通过上述的实例,可以看到:当有不同的访问者的时候只需要添加Visitor的实现类即可,而不同的访问者对该家庭的访问结果可能不同,比如某一个不在家等(即算法不同)。

迭代器模式

迭代器模式(Iterator Pattern),用于属顺序访问集合对象的元素(及遍历),这设计模式不需要知道集合对象底层是用何种结构存储数据的,只需要使用其迭代器就可以遍历。通过将Iterator聚合至存储的实体类中,对外就可以获得其迭代器进行遍历。

迭代器模式需要使用:java.util.Iterator接口。

优点:增加迭代器方便,简化聚合类,在一个聚合上可以有多个遍历(见下面实例种的Client种的遍历);

如下实例:

  • 需求:对于全国省份中城市的统计,再底层有两种方式的存储方式(数组和List),两种存储结构的遍历方式不同,要求使用一种遍历方式实现全省份中的城市的遍历。
  • ProvinceIterator:实现了java中Interater方法;其初始化的时候需要提供给迭代类型的数据集合(数组或List);主要实现hasNext()方法和next()方法提供遍历;
  • Province:省份接口,定义的对省份的基本操作方法:1.获取省份名称、2.添加城市、3.获取迭代器;
  • ProvinceType1、ProvinceType1:两种不同存储方式省份实现类;
  • City:城市对象类;
  • Client:对省份实体类的初始化,并使用迭代器进行遍历。

在这里插入图片描述

ProvinceType1Iterator:

public class ProvinceType1Iterator implements Iterator {
    // 数据集
    private City city[];
    // 当前位置
    private int index;
    // 数据集初始化
    public ProvinceType1Iterator(City[] city) {
        this.city = city;
    }
    // 判断是否还有剩余元素
    @Override
    public boolean hasNext() {
        if(index > city.length || city[index] == null){
            return false;
        }
        return true;
    }
    // 获取下一个元素,并使标记+1
    @Override
    public Object next() {
        return city[index++];
    }
}

ProvinceType2Iterator:

public class ProvinceType2Iterator implements Iterator<City> {
    // 待遍历的数据集
    private List<City> city;
    // 当前遍历到的位置
    private int index = 0;
    // 初始化数据集
    public ProvinceType2Iterator(List<City> city) {
        this.city = city;
    }
    // 判断是否还有元素
    @Override
    public boolean hasNext() {
        if(index > city.size()-1){
            return false;
        }
        return true;
    }
    // 获取下一个元素,并使位置标记+1
    @Override
    public City next() {
        return city.get(index++);
    }
}

Province:

/**
 * 省份信息
 */
public interface Province {
    // 获取省份名称
    String getName();
    // 添加城市
    void addCity(String name);
    // 获取迭代器
    Iterator getIterator();
}

ProvinceType1:

/**
 * 第一种类型省份城市数据集合
 * 使用数组存放
 */
public class ProvinceType1 implements Province{
    // 省份名称
    private String name;
    // 城市数据集
    private City[] cities;
    // 当前最后元素位置,便于添加元素
    private int index;
    // 初始化省份信息
    public ProvinceType1(String name) {
        this.name = name;
        cities = new City[15];
    }
    // 获取省份名称
    @Override
    public String getName() {
        return name;
    }
    // 添加城市
    @Override
    public void addCity(String name) {
        City city = new City(name);
        cities[index++] = city;
    }
    // 获取第一种类型的省份的迭代器
    @Override
    public Iterator getIterator() {
        return new ProvinceType1Iterator(cities);
    }
}

ProvinceType2:

/**
 * 第二种类型省份城市数据集合
 * 使用集合存放
 */
public class ProvinceType2 implements Province{
    // 名称
    private String name;
    // 城市数据集
    private List<City> cityList;
    // 初始化省份信息
    public ProvinceType2(String name) {
        this.name = name;
        cityList = new ArrayList<>();
    }
    // 获取省份名称
    @Override
    public String getName() {
        return name;
    }
    // 添加城市
    @Override
    public void addCity(String name) {
        City city = new City(name);
        cityList.add(city);
    }
    // 获取该省份的迭代器
    @Override
    public Iterator getIterator() {
        return new ProvinceType2Iterator(cityList);
    }
}

City:

public class City {
    private String name;

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

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

Client:

public class Client {
    public static void main(String[] args) {
        List<Province> list = new ArrayList<>();
        ProvinceType1 zj = new ProvinceType1("浙江");
        ProvinceType2 js = new ProvinceType2("江苏");
        list.add(zj);
        list.add(js);
        zj.addCity("杭州");
        zj.addCity("宁波");
        zj.addCity("嘉兴");
        js.addCity("苏州");
        js.addCity("南京");
        js.addCity("无锡");

        printAll(list);
        /**
         * -------------浙江------------
         * City{name='杭州'}
         * City{name='宁波'}
         * City{name='嘉兴'}
         * -------------江苏------------
         * City{name='苏州'}
         * City{name='南京'}
         * City{name='无锡'}
         */

        printCities(js.getIterator());
        /**
         * City{name='苏州'}
         * City{name='南京'}
         * City{name='无锡'}
         */
    }
    // 打印全部省份的城市信息
    public static void printAll(List<Province> list){
        for (Province p : list){
            System.out.println("-------------" + p.getName()+ "------------");
            Iterator iterator = p.getIterator();
            while(iterator.hasNext()){
                System.out.println(iterator.next());
            }
        }
    }
    // 打印某个省份的城市
    public static void printCities(Iterator iterator){
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
    
}

通过上面的示例可以看到,对于两种不同的存储方式的实体,在使用迭代器模式(实现迭代器接口)后,可以被同时遍历出来(见Client类中的printAll()方法),同时在添加其他类型的存储方式时,也只需要创建其对应的Iterator即可使用,符合OCP原则。

JDK中的使用

典型的是ArrayList,看下面的UML图以及部分源码:

在这里插入图片描述

// 对外暴露的方法,直接获得当前arrayList对象的迭代器
public Iterator<E> iterator() {
    return new Itr();
}

// 这是它的内部类,直接实现类Iterator接口,并实现方法
private class Itr implements Iterator<E> {
    int cursor;       // index of next element to return
    int lastRet = -1; // index of last element returned; -1 if no such
    int expectedModCount = modCount;

    Itr() {}
	
    public boolean hasNext() {
        return cursor != size;
    }

    @SuppressWarnings("unchecked")
    public E next() {
        checkForComodification();
        int i = cursor;
        if (i >= size)
            throw new NoSuchElementException();
        Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length)
            throw new ConcurrentModificationException();
        cursor = i + 1;
        return (E) elementData[lastRet = i];
    }
    // 。。。。。other methods
}

通过源码发现:

  • ArrayLits中使用了迭代器,并且作为内部类直接放在其内部,所以它与上面的示例不同,示例是将迭代器聚合到类中在使用,这里是内部内类因此可以直接使用ArrayLits的原始数据:

    // ArrayLits成员变量
    transient Object[] elementData;
    
    // 上面源码中,直接操作之
    Object[] elementData = ArrayList.this.elementData;
    
  • 同理,可以看到List接口其他的实现类,也使用了迭代器。

观察者模式

观察者模式(Observer Pattern)体现的是对象间的一对多关系。比如班主任之于学生——当班主任发生变化的时候就会通知全部的学生;比如天气预报接口之于网站——天气变化会通知各个接入的网站进行更新。观察者模式就是这样的模式,当一个对象的状态方式改变,依赖于它的全部对象便会随之改变。

优点:实现观察者与被观察者的解耦;实现触发机制。

缺点:通知全部观察者效率不高且有些情况下不需要全部通知。

如下实例:

  • 需求:有一气象站Subject实时发布最新气象数据,多家网站接入该气象站获取其数据,在气象站跟新数据后通知所有接入的网站实现同步更新。
  • ISubject:被观察者接口,定义被观察者的基本操作:添加观察者;删除观察者;更新数据;同步推送;
  • WeatherSubject:被观察者实现类,对方法实现,并设定自己管理的数据;
  • Observer:观察者接口,定义观察者的基本操作,更新数据,和获得数据;
  • Website1、Website2:具体的观察者,接入到被观察者,实现具体方法;
  • Client:实现观察者接入到被观察者中;被观察者更新数据同步到观察者。

在这里插入图片描述

ISubject:

/**
 * 主题接口
 */
public interface ISubject {

    void addObserver(Observer observer);

    void removeObserver(Observer observer);

    void setData(float temperature, float humidity);

    void notifyAllObserver();
}

WeatherSubject:

/**
 * 主题实现类
 */
public class WeatherSubject implements ISubject{
    // 数据信息
    private float temperature;
    private float humidity;
    // 已接入的观察者Observer
    private List<Observer> observerList;

    public WeatherSubject() {
        this.observerList = new ArrayList<>();
    }
    // 添加接入的观察者
    @Override
    public void addObserver(Observer observer) {
        observerList.add(observer);
    }
    // 删除观察者
    @Override
    public void removeObserver(Observer observer) {
        observerList.remove(observer);
    }
    // 更新主题中的信息,同时调用提醒方法
    @Override
    public void setData(float temperature, float humidity) {
        this.temperature = temperature;
        this.humidity = humidity;
        // 调用提示方法
        notifyAllObserver();
    }
    // 提示所有观察者数据更新,并将数据发送给他进行更新
    @Override
    public void notifyAllObserver() {
        for(Observer o : observerList){
            o.update(this.temperature, this.humidity);
        }
    }
}

Observer:

/**
 * 观察者接口
 */
public interface Observer {
    // 获取观察者信息
    String getData();
    // 跟新观察者信息
    void update(float temperature, float humidity);
}

Website1:

/**
 * 网站1
 */
public class Website1 implements  Observer {

    private float temperature;
    private float humidity;

    @Override
    public String getData(){
        return "temperature: " + this.temperature + "  humidity: " + this.humidity;
    }

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

Website2:

/**
 * 网站2
 */
public class Website2 implements Observer{

    private float temperature;
    private float humidity;

    @Override
    public String getData(){
        return "temperature: " + this.temperature + "  humidity: " + this.humidity;
    }

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

Client:

public class Client {
    public static void main(String[] args) {
        // 创建数据中心(气象站)
        WeatherSubject subject = new WeatherSubject();
        // 网站
        Observer website1 = new Website1();
        Observer website2 = new Website2();
        // 网站接入气象站
        subject.addObserver(website1);
        subject.addObserver(website2);
        // 气象站更新数据
        subject.setData(25,60);
        System.out.println("website1: " + website1.getData());
        System.out.println("website2: " + website2.getData());
        /**
         * website1: temperature: 25.0  humidity: 60.0
         * website2: temperature: 25.0  humidity: 60.0
         */
        // 气象站更新数据
        subject.setData(35,20);
        System.out.println("website1: " + website1.getData());
        System.out.println("website2: " + website2.getData());
        /**
         * website1: temperature: 35.0  humidity: 20.0
         * website2: temperature: 35.0  humidity: 20.0
         */
    }
}

在JDK中的Observable类中使用到。

中介者模式

中介者模式(Mediator Pattren)可以降低多个类之间通信复杂性。在子系统中的各个对象之间不直接通信,而是通过中介者进行间接通信,由中介者协调处理,以实现子系统之间的解耦。

使用场景:一个子系统中的多个类相互耦合,形成网状结构。

优点:降低类的复杂性和耦合性,符合迪米特原则。

缺点:由中介者协调,当中介者出现问题会导致整个系统出问题;且中介者会变得很大,难以维护。

如下:

  • 需求:Person1向Person2发送消息,不能直接发送,而是通过中介者转发实现。如下图,可以看到Person与Person之间是没有联系的(解耦)。
  • Mediator:中介者接口由MsgMediator实现,确定基本的方法:注册Colleague和接受中间消息;
  • Clleague:抽象类,定义了子系统中的对象的基本方法:接收消息和发送消息;
  • Person1、Person2:具体实现类。
  • Client:实现Pserson之间的通信。

在这里插入图片描述

Mediator:

/**
 * 中介者接口
 */
public interface Mediator {
    // 将同事对象Colleague注册到中介者中
    void register(String name,Colleague colleague);
    // 中介者转发消息
    void getMsg(String name,String s);
}

Msgmediator:

/**
 * 中介者实体
 */
public class Msgmediator implements Mediator{
    // 集合:存储Colleague对象
    private Map<String,Colleague> map;

    public Msgmediator() {
        map = new HashMap<>();
    }
    // 添加Colleague对象
    @Override
    public void register(String name, Colleague colleague) {
        map.put(name, colleague);
    }
    // 煮饭消息
    @Override
    public void getMsg(String name,String s) {
        if (map.containsKey(name)){
            map.get(name).getMsg(s);
        }
    }
}

Colleague:

/**
 * Colleague抽象类
 */
public abstract class Colleague {
    public abstract void getMsg(String s);
    public abstract void sendMsg();
}

Person1:

/**
 * Colleague实例1
 */
public class Person1 extends Colleague{

    private Mediator mediator;
    // 注册到中介者
    public Person1(Mediator mediator) {
        this.mediator = mediator;
        mediator.register("person1", this);
    }
    // 接受消息
    @Override
    public void getMsg(String s) {
        System.out.println("Person1 get msg : " + s);
    }
    // 发送消息
    @Override
    public void sendMsg() {
        mediator.getMsg("person2","hello, i am person1");
    }
}

Person2:

/**
 * 实例2,同Person1
 */
public class Person2 extends Colleague{

    private Mediator mediator;

    public Person2(Mediator mediator) {
        this.mediator = mediator;
        mediator.register("person2", this);
    }

    @Override
    public void getMsg(String s) {
        System.out.println("person2 get msg : " + s);
    }

    @Override
    public void sendMsg() {
        mediator.getMsg("person1","hello, i am person2");
    }
}

Client:

public class Client {
    public static void main(String[] args) {
        Msgmediator msgmediator = new Msgmediator();
        Person1 person1 = new Person1(msgmediator);
        Person2 person2 = new Person2(msgmediator);
        person1.sendMsg();
        person2.sendMsg();
        /**
         * person2 get msg : hello, i am person1
         * Person1 get msg : hello, i am person2
         */
    }
}

实例应用:MVC中:C(controller)是M(model)和V(view)的中介者。

备忘录模式

备忘录模式(Memento Pattern)用于保存一个对象的某个状态,当对象被修改之后可以通过备忘录来恢复之前的数据。

备忘录模式可以根据字面意思理解,就是一个备忘的副本,同时也将用户类与备忘录管理类解耦。

优点:提供了对象的状态恢复机制;

缺点:需要额外的资源区存储备忘录信息。

常见场景:撤销操作、回档机制等。

如下:

  • 需求:创建一个游戏类,游戏为章节类游戏(状态);玩家可以对当前游戏进度进行保存(可多次保存),当需要回档的时候,只需要选择该备忘录即可。
  • Game:游戏类,有一个状态——当前游戏进度(章节),提供保存进度方法和读取存档方法;
  • GameMemento:备忘录类,保存了某个时刻Game类的状态;
  • GameCraeTaker:备忘录管理类,保存了各个时候的备忘录,对外提供添加备忘录和读取备忘录的方法;
  • Cient:玩家创建游戏,并在需要的章节创建进行保存,并在合适的时候读档。

在这里插入图片描述

Game:

/**
 * 游戏类
 */
public class Game {
    // 游戏状态
    private String chapter;

    public Game() {
    }
    // 将当前状态添加到备忘录
    public void addMemento(GameCareTaker gameCareTaker){
        gameCareTaker.addMemento(new GameMemento(this.chapter));
    }
    // 回档
    public void recover(GameCareTaker gameCareTaker,int mementoNum){
        GameMemento memento = gameCareTaker.getMemento(mementoNum);
        this.chapter = memento.getChapter();
    }

    public String getChapter() {
        return chapter;
    }

    public void setChapter(String chapter) {
        this.chapter = chapter;
    }

}

GameMemento:

/**
 * 备忘录类,封装了相关的信息
 */
public class GameMemento {
    private String chapter;

    public GameMemento(String chapter) {
        this.chapter = chapter;
    }

    public String getChapter() {
        return chapter;
    }

    public void setChapter(String chapter) {
        this.chapter = chapter;
    }
}

GameCareTaker:

/**
 * caretaker负责对对象的备忘管理
 */
public class GameCareTaker {

    private List<GameMemento> mementos;

    public GameCareTaker() {
        this.mementos = new ArrayList<>();
    }

    public void addMemento(GameMemento memento){
        mementos.add(memento);
    }

    public GameMemento getMemento(int mementoNum){
        return mementos.get(mementoNum);
    }
}

Client:

public class Client {
    public static void main(String[] args) {
        // 创建游戏
        Game game = new Game();
        GameCareTaker gameCareTaker = new GameCareTaker();
        // 开始第一章
        game.setChapter("第一章");
        System.out.println("当前游戏在:" + game.getChapter());
        // 保存备忘录
        game.addMemento(gameCareTaker);
        // 开始第五章
        game.setChapter("第五章");
        System.out.println("当前游戏在:" + game.getChapter());
        // 保存到备忘录
        game.addMemento(gameCareTaker);
        // 开始第六章
        game.setChapter("第六章");
        System.out.println("当前游戏在:" + game.getChapter());
        // 回档到第五章(第二次的备忘录)
        game.recover(gameCareTaker, 1);
        System.out.println("当前游戏在:" + game.getChapter());
    }
}
/*
* 当前游戏在:第一章
* 当前游戏在:第五章
* 当前游戏在:第六章
* 当前游戏在:第五章
*/

解释器模式

解释器模式(Interpreter Pattern)提供了评估语言的语法或表达式的方式。

该模式通过一个抽象类定义对一个表达式的解析,比如对四则运算表达式“a+b/c”的解析。

优点:扩展性好,对于添加功能的时候,只需要添加新的解释器即可,不许哟啊在原来的代码上进行添加修改。

缺点:使用的场景比较少;对于复杂的表达式难以维护。

状态模式

状态模式(State Parrten)中,类的操作根据类的状态改变而改变。

如:对于一个人,在青年状态时的操作为学习,在壮年状态时操作为工作,早老年状态时操作为养老等,根据实际的状态而变化其操作。

在状态模式中,有如下构成:

  • Context:上下文,用于保存该类的一个状态,在不同状态下,对于同一个方法具有不同的行为。

  • State:状态类,由一个抽象类派生出来具体的许多子状态;在抽象类中定义了一个对象的所有的可能操作;

    子类状态对其操作方法根据自身的需要进行重写。

优点:封装了状态的转换;将一个类的所有状态分装到了一个类中,只需要修改该类的状态就可以改变其行为;

缺点:状态类增加,时系统的而复杂度增加。

如下:

  • 需求:用户在某平台上需要上传一个视频作品,在此期间有两个状态(审核、通过);上传时的初始状态为审核,审核通过之后进入完成状态,才能进行播放。
  • AbsState:状态抽象类,定义了所有状态可能的操作,具体状态根据实际情况重写相关方法;
  • AuditState:审核状态,该状态下作品等待审核且不能播放;
  • PassState:通过状态,该状态下作品可以被播放,不需要再被审核;
  • ContributionContext:投稿上下文,该类中枚举了该稿件的所有状态,在不同状态下调用相同的方法会有不同的行为;
  • Client:客户端,创建稿件,并根据其状态执行操作。

在这里插入图片描述

ContributionContext:

/**
 * 投稿类的上下文
 */
public class ContributionContext {
    private AbsState state;
    // 枚举状态
    AbsState auditState = new AuditState(this);
    AbsState passState = new PassState(this);
    // 初始化状态
    public ContributionContext() {
        this.state = auditState;
    }
    // 审核操作
    public void audit(){
        state.audit();
    }
    // 播放操作
    public void play(){
        state.play();
    }

    public AbsState getState() {
        return state;
    }

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

    public AbsState getAuditState() {
        return auditState;
    }

    public void setAuditState(AbsState auditState) {
        this.auditState = auditState;
    }

    public AbsState getPassState() {
        return passState;
    }

    public void setPassState(AbsState passState) {
        this.passState = passState;
    }
}

AbsState:

/**
 * 状态抽象类
 */
public abstract class AbsState {
    // 修改
    public abstract void audit();
    // 播放
    public abstract void play();
}

AuditState:

/**
 * 审核状态
 */
public class AuditState extends AbsState{

    private ContributionContext context;

    public AuditState(ContributionContext context) {
        this.context = context;
    }

    @Override
    public void audit() {
        System.out.println("审核通过~");
        // 审核通过,并切换状态
        context.setState(context.getPassState());
    }

    @Override
    public void play() {
        System.out.println("审核未通过,不能播放~");
    }
}

PassState:

/**
 * 审核通过状态类
 */
public class PassState extends AbsState{
    private ContributionContext context;

    public PassState(ContributionContext context) {
        this.context = context;
    }

    @Override
    public void audit() {
        System.out.println("已审核,不许需要再次审核~");
    }

    @Override
    public void play() {
        System.out.println("正在播放~");
    }
}

Client:

public class Client {
    public static void main(String[] args) {
        ContributionContext context = new ContributionContext();
        // 直接播放
        context.play();
        // 审核
        context.audit();
        // 再审核
        context.audit();
        // 播放
        context.play();
        /**
         * 审核未通过,不能播放~
         * 审核通过~
         * 已审核,不许需要再次审核~
         * 正在播放~
         */
    }
}

策略模式

策略模式(Strategy Pattern)实现一个类的行为再运行时更改。该类通过在运行时修改其策略来实现行为的更改。

使用场景:如Person类有多个继承,不同的子类拥有与Person类相近的新为,在一些特别的类中可能会对某个方法进行重写;也有特殊情况下:一个类属于Person范畴,但是其重写Person的全部方法。对于这种情况单纯使用继承解决就不显得那么灵活,就可以使用策略模式。通过聚合或组合的方式将策略分装到类中。

优点:行为变化灵活;可扩展性好;避免多重判断;

缺点:策略类多样不利于维护。

如下:

  • 需求:有一个演员类,其行为是表演,但是表演的节目不确定需要根据实际情况灵活改变(唱歌、跳舞、书法)。
  • Strategy:策略接口,定义了一个表演的抽象方法,具体表演类型有其实现类进行具体实现;
  • Sing、Dance、Calligraphy:具体的策略类,实现的接口中的方法。
  • Actor:演员类,通过聚合将策略分装到类中,根据策略的不同将执行不同的行为。也可以随时修改其策略;
  • Client:客户端,创建演员类,并赋予策略使其执行相关的行为。

在这里插入图片描述

Strategy:

/**
 * 策略接口
 */
public interface Strategy {
    void performance();
}

Sing:

/**
 * 唱歌表演
 */
public class Sing implements Strategy{
    @Override
    public void performance() {
        System.out.println("唱歌~");
    }
}

Dance:

/**
 * 跳舞表演
 */
public class Dance implements Strategy{
    @Override
    public void performance() {
        System.out.println("跳舞~");
    }
}

Calligraphy:

/**
 * 书法表演
 */
public class Calligraphy implements Strategy{
    @Override
    public void performance() {
        System.out.println("书法~");
    }
}

Actor:

/**
 * 演员类
 */
public class Actor {
    // 演员行为策略
    private Strategy strategy;

    public Actor(Strategy strategy) {
        this.strategy = strategy;
    }
    // 根据策略的不同执行不同的方法
    public void performance(){
        if (strategy != null){
            strategy.performance();
        }
    }
    // 重新设置策略
    public Strategy getStrategy() {
        return strategy;
    }

    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }
}

Client:

public class Client {
    public static void main(String[] args) {
        // 创建一个演员,策略为Sing
        Actor actor = new Actor(new Sing());
        actor.performance();
        // 设置策略为Dance
        actor.setStrategy(new Dance());
        actor.performance();
        // 设置策略为Calligraphy
        actor.setStrategy(new Calligraphy());
        actor.performance();
        /**
         * output:
         * 唱歌~
         * 跳舞~
         * 书法~
         */
    }
}

JDK中的使用

Comparator接口的使用。

  • Comaprator就是一个策略接口,其内部有一个方法——compare();
  • 实现该接口之后重写compare()方法就是具体的策略,比如升序、降序等;
  • 在集合List或Arrays中调用sort()方法时就会传入这个具体的策略,根据策略执行相关的行为。

责任链模式

责任链模式(Chain of Responsibility Patterb)为请求创建了一个接收者对象的链,当第一个对象不能处理该请求时会将该请求传给下一个接收者,再不行再传,直到找到合适的处理方式为止。

在责任链模式中是通过一个接收者中聚合了另一个接收者以实现链(或环)。

实际应用场景:servlet中的Filter链、拦截器等

优点:解耦,将请求对象与接收对象分离;使接收者处理的方式更灵活;在添加新的接收者的时候会很方便。

缺点:如果链很长,而且总是被链的最后的接收者接收,那么会消耗大量的资源,系统性能收到影响。

如下:

  • 需求:找位置,对于三个用户(tom、jerry、lucy)都有自己特定的位置,每个人只能坐自己的位置,以此实现他们找到自己的位置坐下。
  • Person:用户类,封装了用户的姓名信息,也就是责任链模式中的请求者;
  • AbsSeat:作为接收者的抽象类,统一接收者的方法和属性(在类中维护了一个其他的接受者);
  • TomSeat、JerrySeat、LucySeat:三个人个自的作为(接受者),每个作为只能坐下对应的用户;
  • Client:客户端,创建用户、接收者并形成责任链,在将请求发送给责任链,开始寻找个自的座位。

在这里插入图片描述

Person:

/**
 * 用户,接收者
 */
public class Person {
    private String name;

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

    public String getName() {
        return name;
    }
}

AbsSeat:

/**
 * 接收者抽象类
 */
public abstract class AbsSeat {
    // 下一个接收者
    protected AbsSeat seat;
    // 设置下一个接收者
    public void setSeat(AbsSeat seat) {
        this.seat = seat;
    }
    // 各个实现对象的具体逻辑
    public abstract void sitDown(Person person);
}

TomSeat:

/**
 * tom 的作为
 */
public class TomSeat extends AbsSeat{

    @Override
    public void sitDown(Person person) {
        if(person.getName() != null && person.getName().equals("tom")){
            System.out.println("tom find his seat");
        }else{
            // 如果来的不是tom,则寻找下一个对象是否匹配
            seat.sitDown(person);
        }
    }
}

LucySeat:

/**
 * lucy 的对象
 */
public class LucySeat extends AbsSeat{
    @Override
    public void sitDown(Person person) {
        if(person.getName() != null && person.getName().equals("lucy")){
            System.out.println("lucy find his seat");
        }else{
            seat.sitDown(person);
        }
    }
}

JerrySeat:

/**
 * jerry 的作为
 */
public class JerrySeat extends AbsSeat{
    @Override
    public void sitDown(Person person) {
        if(person.getName() != null && person.getName().equals("jerry")){
            System.out.println("jerry find his seat");
        }else{
            seat.sitDown(person);
        }
    }
}

Client:

public class Client {
    public static void main(String[] args) {
        Person tom = new Person("tom");
        // 创建对象并形成责任链
        TomSeat tomSeat = new TomSeat();
        LucySeat lucySeat = new LucySeat();
        JerrySeat jerrySeat = new JerrySeat();
        tomSeat.setSeat(lucySeat);
        lucySeat.setSeat(jerrySeat);
        jerrySeat.setSeat(tomSeat);

        // tom开始寻找自己的位置
        lucySeat.sitDown(tom);
        // tom find his seat

        // StackOverflowError
        // 由于该责任链时一个循环,没有该用户的位置将会导致栈溢出,可设置判定条件结束循环
        lucySeat.sitDown(new Person("amy"));

    }
}
public abstract void sitDown(Person person);

}


**TomSeat:**

```java
/**
 * tom 的作为
 */
public class TomSeat extends AbsSeat{

    @Override
    public void sitDown(Person person) {
        if(person.getName() != null && person.getName().equals("tom")){
            System.out.println("tom find his seat");
        }else{
            // 如果来的不是tom,则寻找下一个对象是否匹配
            seat.sitDown(person);
        }
    }
}

LucySeat:

/**
 * lucy 的对象
 */
public class LucySeat extends AbsSeat{
    @Override
    public void sitDown(Person person) {
        if(person.getName() != null && person.getName().equals("lucy")){
            System.out.println("lucy find his seat");
        }else{
            seat.sitDown(person);
        }
    }
}

JerrySeat:

/**
 * jerry 的作为
 */
public class JerrySeat extends AbsSeat{
    @Override
    public void sitDown(Person person) {
        if(person.getName() != null && person.getName().equals("jerry")){
            System.out.println("jerry find his seat");
        }else{
            seat.sitDown(person);
        }
    }
}

Client:

public class Client {
    public static void main(String[] args) {
        Person tom = new Person("tom");
        // 创建对象并形成责任链
        TomSeat tomSeat = new TomSeat();
        LucySeat lucySeat = new LucySeat();
        JerrySeat jerrySeat = new JerrySeat();
        tomSeat.setSeat(lucySeat);
        lucySeat.setSeat(jerrySeat);
        jerrySeat.setSeat(tomSeat);

        // tom开始寻找自己的位置
        lucySeat.sitDown(tom);
        // tom find his seat

        // StackOverflowError
        // 由于该责任链时一个循环,没有该用户的位置将会导致栈溢出,可设置判定条件结束循环
        lucySeat.sitDown(new Person("amy"));

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值