设计模式——个人学习之观察者模式

观察者模式

简介

如果有这样一个场景,比如:我们在游戏的时候,当我们完成一个主线任务的时候,可以能会同时开启多个支线任务,因此我们的支线任务一定是要等主角完成主线任务后,根据主角完成的质量或者说结果来开启对应的支线任务,因此支线任务就像一个观察者,一直盯着主角主线任务完成到哪里了,什么时候它才能公布出来,这就是观察者模式的实际场景应用。

观察者(Observer)模式的定义:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。它是对象行为型模式。

这是观察者模式的UML图:

img

从图中我们可以罗列出它的结构:

  1. 抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
  2. 具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
  3. 抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
  4. 具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。

优缺点

观察者模式是一种对象行为型模式,其主要优点如下:

  1. 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。
  2. 目标与观察者之间建立了一套触发机制。

它的主要缺点如下:

  1. 目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。
  2. 当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。

代码实现

抽象主题角色:

package com.example.demo.basis.design.observer;

import java.util.ArrayList;

/**
 * @author: sunzhinan
 * @create: 2020-08-11 22:29
 * @description: 抽象角色类
 */
public abstract class Role {
    //定义一个集合,里面是存放这个角色有关的支线任务
    public ArrayList<SubTask> subTasksList = new ArrayList<>();

    //添加支线任务的方法
    public void putTask(SubTask subTask){
        subTasksList.add(subTask);
    }

    //子类实现的方法
    public abstract void notifyTask();

}

具体主题角色:

package com.example.demo.basis.design.observer;

/**
 * @author: sunzhinan
 * @create: 2020-08-11 22:39
 * @description: 主角1
 */
public class ProtagonistOne extends Role{
    @Override
    public void notifyTask() {
        System.out.println("-----开启支线任务-----");
        for ( SubTask subTask : subTasksList) {
            subTask.callMe();
        }
    }
}

抽象观察者角色:

package com.example.demo.basis.design.observer;

/**
 * 支线任务接口
 */
public interface SubTask {
    public void callMe();
}

具体观察者角色:

package com.example.demo.basis.design.observer;

/**
 * @author: sunzhinan
 * @create: 2020-08-11 22:31
 * @description: 支线任务1
 */
public class SubTaskOne implements SubTask{
    @Override
    public void callMe() {
        System.out.println("支线任务1已开启");
    }
}
package com.example.demo.basis.design.observer;

/**
 * @author: sunzhinan
 * @create: 2020-08-11 22:33
 * @description: 支线任务2
 */
public class SubTaskTwo implements SubTask{
    @Override
    public void callMe() {
        System.out.println("支线任务2已开启");
    }
}

测试类:

package com.example.demo.basis.design.observer;

/**
 * @author: sunzhinan
 * @create: 2020-08-11 22:43
 * @description: 测试类
 */
public class Test {
    public static void main(String[] args) {
        Role role = new ProtagonistOne();
        role.putTask(new SubTaskOne());
        role.putTask(new SubTaskTwo());

        role.notifyTask();
    }
}

结果:
    -----开启支线任务-----
	支线任务1已开启
	支线任务2已开启

上面的示例就一个简单的观察者模式基本框架,在这里我们可以丰富一下它,比如我们可以新加一个事件,当出现某个事件的时候,我们开启对应的支线任务。

事件:

package com.example.demo.basis.design.observer;

/**
 * @author: sunzhinan
 * @create: 2020-08-11 22:50
 * @description: 事件——通过泛型可以衍生出不同的角色事件类型
 */
public abstract class TaskEvent<T> {

    String taskName;

    String taskType;

    abstract T getSource();
}
package com.example.demo.basis.design.observer;

/**
 * @author: sunzhinan
 * @create: 2020-08-11 22:51
 * @description: Role角色事件类型
 */
public class OneTaskEvent extends TaskEvent<Role>{


    Role role;

    public OneTaskEvent(String taskName, String taskType, Role role) {
        this.taskName = taskName;
        this.taskType = taskType;
        this.role = role;
    }

    @Override
    Role getSource() {
        return this.role;
    }
}

其他类也需要做相应的变化

抽象主题角色:

package com.example.demo.basis.design.observer;

import java.util.ArrayList;

/**
 * @author: sunzhinan
 * @create: 2020-08-11 22:29
 * @description: 抽象角色类
 */
public abstract class Role {
    String roleType;

    public Role(String roleType) {
        this.roleType = roleType;
    }

    //定义一个集合,里面是存放这个角色有关的支线任务
    public ArrayList<SubTask> subTasksList = new ArrayList<>();

    //添加支线任务的方法
    public void putTask(SubTask subTask){
        subTasksList.add(subTask);
    }

    //子类实现的方法
    public abstract void notifyTask();

    public String getRoleType() {
        return roleType;
    }

    public void setRoleType(String roleType) {
        this.roleType = roleType;
    }

}

具体主题角色:

package com.example.demo.basis.design.observer;

/**
 * @author: sunzhinan
 * @create: 2020-08-11 22:39
 * @description: 主角1
 */
public class ProtagonistOne extends Role{
    public ProtagonistOne(String roleType) {
        super(roleType);
    }

    @Override
    public void notifyTask() {
        System.out.println("-----开启支线任务-----");
        OneTaskEvent oneTaskEvent = new OneTaskEvent("主线任务1", "kill boss", this);
        for ( SubTask subTask : subTasksList) {
            subTask.callMe(oneTaskEvent);
        }
    }
}

抽象观察者角色:

package com.example.demo.basis.design.observer;

/**
 * 支线任务接口
 */
public interface SubTask {
    public void callMe(TaskEvent taskEvent);
}

具体观察者角色:

package com.example.demo.basis.design.observer;

/**
 * @author: sunzhinan
 * @create: 2020-08-11 22:31
 * @description: 支线任务1
 */
public class SubTaskOne implements SubTask{
    @Override
    public void callMe(TaskEvent taskEvent) {
        System.out.println("支线任务1已开启");

        System.out.println("主线任务类型是 : " + taskEvent.taskType + " 已完成");
    }
}
package com.example.demo.basis.design.observer;

/**
 * @author: sunzhinan
 * @create: 2020-08-11 22:33
 * @description: 支线任务2
 */
public class SubTaskTwo implements SubTask{
    @Override
    public void callMe(TaskEvent taskEvent) {
        System.out.println("支线任务2已开启");
        Role source = (Role) taskEvent.getSource();
        System.out.println("主角角色是 : " + source.getRoleType());
        System.out.println("主线任务是 : " + taskEvent.taskName + " 已完成");

    }
}

测试类:

package com.example.demo.basis.design.observer;

/**
 * @author: sunzhinan
 * @create: 2020-08-11 22:43
 * @description: 测试类
 */
public class Test {
    public static void main(String[] args) {
        Role role = new ProtagonistOne("法师");
        role.putTask(new SubTaskOne());
        role.putTask(new SubTaskTwo());

        role.notifyTask();
    }
}

结果:
    -----开启支线任务-----
    支线任务1已开启
    主线任务类型是 : kill boss 已完成
    支线任务2已开启
    主角角色是 : 法师
    主线任务是 : 主线任务1 已完成

所以可以看出,这样的观察者模式内容更加丰富,同时也能感觉代码的可维护性增强了。
其实观察者模式在实际的运用中有很多,我们常说的事件,比如js中的事件,spring中的事件等等都是使用的这个设计模式。

参考文档:《GoF设计模式》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值