设计模式之观察者模式(委托机制)

观察者模式和发布/订阅模式

  • 概念
  • 观察者模式和发布/订阅模式区别
  • 为什么要使用委托机制
  • 观察者模式和委托机制类图
  • 观察者模式和委托机制代码实例

概念

观察者模式是一种一对多的依赖关系,让多个观察者对象同时监听同个主题对象。当这个主题对象在状态发生变化时,会通知所有注册到主题对象的观察者对象,使他们能够自动更新自己。

观察者模式和发布/订阅模式区别

观察者模式:

比较概念的解释是,目标和观察者是基类,目标提供维护观察者的一系列方法,观察者提供更新接口。具体观察者和具体目标继承各自的基类,然后具体观察者把自己注册到具体目标里,在具体目标发生变化时候,调度观察者的更新方法。

比如有个“天气中心”的具体目标A,专门监听天气变化,而有个显示天气的界面的观察者B,B就把自己注册到A里,当A触发天气变化,就调度B的更新方法,并带上自己的上下文

图1

发布/订阅模式:

比较概念的解释是,订阅者把自己想订阅的事件注册到(调度中心),当该事件触发时候,发布者发布该事件到调度中心(顺带上下文),由调度中心统一调度订阅者注册到调度中心的处理代码。

比如有个界面是实时显示天气,它就订阅天气事件(注册到调度中心,包括处理程序),当天气变化时(定时获取数据),就作为发布者,发布天气信息到调度中心,调度中心就调度订阅者的天气处理程序。

图2

总结:

从两张图片可以看到,最大的区别是调度的地方。

虽然两种模式都存在订阅者和发布者(具体观察者可认为是订阅者、具体目标可认为是发布者),但是观察者模式是由具体目标调度的,而发布/订阅模式是统一由调度中心调的,所以观察者模式的订阅者与发布者之间是存在依赖的,而发布/订阅模式则不会

订阅者模式,有两种:

一种是以前的RSS Reeder的那种订阅者方法,用户对指定内容申请订阅,内容发布者记录下来,定期发送更新内容给订阅者。这种方式不需要一个调度中心的存在,由发布者采用分发方式分别发送给订阅者,可以一次性发送或者慢慢发。

第二种是现在的消息分发,如redis, ZeroMQ(消息队列)等,存在一个调度中心,由调度中心负责所有的订阅管理、分发管理,发布者只需要发送一次,其他的事情就交给调度中心来处理。
观察者模式,所说的相当于第一种订阅者模式

消息队列发布/订阅者模型:

在这里插入图片描述

为什么要使用委托机制

观察者模式不好之处就是:如果想因触发某个事件通知观察者,必须要实现抽象观察者接口,而若是第三方类库不能修改源码,则只能使用委托机制进行通知,还有就是实现抽象观察者对象接口都是同个方法,但是有时候可能为add、delete操作而不是仅仅update操作。 所以java通过反射实现的委托机制可以通知执行任何一个类的任何一个方法

观察者模式和委托机制类图

在这里插入图片描述

观察者模式和委托机制代码实例

观察者模式代码

Observer 抽象观察者接口


/**
 * @author duanyimiao
 * @create 2018-10-04 2:30 PM
 * @description 抽象观察者
 **/
public interface Observer {

    void update(String state);
}

Subject 抽象主题类

/**
 * @author duanyimiao
 * @create 2018-10-04 2:15 PM
 * @description 抽象主题类(通知者)
 **/
public abstract class Subject {

    protected String state;

    //依赖抽象观察者,符合依赖倒置原则 具体依赖抽象,抽象不依赖具体
    protected List<Observer> observerList = new ArrayList<>();

    public abstract void addObserver(Observer observer);

    public abstract void deleteObserver(Observer observer);

    public abstract void notifyUpdate();

    public String getState() {
        return state;
    }

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

ConcreteSubject 具体主题实现类

/**
 * @author duanyimiao
 * @create 2018-10-04 2:36 PM
 * @description
 **/
public class ConcreteSubject extends Subject {

    @Override
    public void addObserver(Observer observer) {
        observerList.add(observer);
    }

    @Override
    public void deleteObserver(Observer observer) {
        observerList.remove(observer);
    }

    @Override
    public void notifyUpdate() {
        for (Observer observer : observerList) {
            observer.update(state);
        }
    }

}

ConcreteObserver1 具体观察者类

/**
 * @author duanyimiao
 * @create 2018-10-04 2:40 PM
 * @description 具体抽象者
 **/
public class ConcreteObserver1 implements Observer {
    //依赖抽象主题类
    private Subject subject;

    public ConcreteObserver1(Subject subject) {
        this.subject = subject;
    }

    @Override
    public void update(String state) {
        System.out.println("ConcreteObserver1 from subject = " + subject.getState());
    }
}

ConcreteObserver2 具体观察者类

/**
 * @author duanyimiao
 * @create 2018-10-04 2:40 PM
 * @description 具体抽象者
 **/
public class ConcreteObserver2 implements Observer {
    @Override
    public void update(String state) {

        System.out.println("ConcreteObserver2=" + state);
    }
}

MainTest 测试类

/**
 * @author duanyimiao
 * @create 2018-10-04 2:42 PM
 * @description
 **/
public class MainTest {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();
        subject.setState("update");
        ConcreteObserver1 concreteObserver1 = new ConcreteObserver1(subject);
        ConcreteObserver2 concreteObserver2 = new ConcreteObserver2();
        subject.addObserver(concreteObserver1);
        subject.addObserver(concreteObserver2);
        //主题对象状态改变了,将state状态通知给其他观察者
        subject.notifyUpdate();

    }
}

输出结果:

ConcreteObserver1 from subject = update
ConcreteObserver2=update

委托机制代码

Event 事件类,封装类某个对象的方法信息(方法名,参数值,参数类型)

/**
 * @author duanyimiao
 * @create 2018-10-04 4:08 PM
 * @description 事件类
 **/
public class Event {
    //方法名
    private String methodName;
    //被委托类对象
    private Object obj;
    //被委托类中方法参数值
    private Object[] params;
    //被委托类中方法参数类型
    private Class[] paramTypes;

    public Event() {
    }

    public Event(String methodName, Object obj, Object ... params) {
        this.methodName = methodName;
        this.obj = obj;
        this.params = params;
        constructParams(params);
    }

    private void constructParams(Object[] params) {
        paramTypes = new Class[params.length];
        for (int i = 0;i<params.length;i++) {
            paramTypes[i] = params[i].getClass();
        }
    }

    public String getMethodName() {
        return methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }

    public Object getObj() {
        return obj;
    }

    public void setObj(Object obj) {
        this.obj = obj;
    }

    public Object[] getParams() {
        return params;
    }

    public void setParams(Object[] params) {
        this.params = params;
    }

    public Class[] getParamTypes() {
        return paramTypes;
    }

    public void setParamTypes(Class[] paramTypes) {
        this.paramTypes = paramTypes;
    }

    /**
     * 通过反射机制根据方法名,参数值,参数类型,进而调用对象中方法来执行
     */
    public void invoke(){
        //通过obj对象获取类字节码对象,然后通过方法名和参数类型获取Method对象
        try {
            Method method = obj.getClass().getMethod(methodName,paramTypes);
            if(method != null){
                //通过Method对象进而执行
                method.invoke(obj,params);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

EventHandler 事件处理器,封装类对Event对象相关的操作

/**
 * @author duanyimiao
 * @create 2018-10-04 4:10 PM
 * @description 事件处理类
 **/
public class EventHandler {
    private List<Event> eventList = new ArrayList<>();

    public void addEvent(String methodName, Object obj, Object ... params) {
        eventList.add(new Event(methodName, obj, params));
    }

    public void eventNotify() {
        for (Event event : eventList) {
            event.invoke();
        }
    }
}

AbstractNotifier 抽象通知者

/**
 * @author duanyimiao
 * @create 2018-10-04 4:52 PM
 * @description 抽象通知者相当于观察者模式的抽象主题类
 **/
public abstract class AbstractNotifier {
    private EventHandler eventHandler = new EventHandler();

    public EventHandler getEventHandler() {
        return eventHandler;
    }

    public void setEventHandler(EventHandler eventHandler) {
        this.eventHandler = eventHandler;
    }

    public abstract void addListener(String methodName,Object obj,Object ... args);

    public abstract void notifyAfterRun();
}

ConcreteNotifier 具体通知者

**
 * @author duanyimiao
 * @create 2018-10-04 4:59 PM
 * @description 具体通知者
 **/
public class ConcreteNotifier extends AbstractNotifier {
    @Override
    public void addListener(String methodName, Object obj, Object... args) {
        getEventHandler().addEvent(methodName, obj, args);
    }

    @Override
    public void notifyAfterRun() {
        getEventHandler().eventNotify();
    }
}

ToolBarListener 具体观察者


/**
 * @author duanyimiao
 * @create 2018-10-04 5:16 PM
 * @description 工具栏监听器 具体的观察者类,不需要抽象观察者
 **/
public class ToolBarListener {

    public void openToolBar(String name){
        System.out.println("open tool bar "+name);
    }
}

DebuggerWindowListener 具体观察者


/**
 * @author duanyimiao
 * @create 2018-10-04 5:16 PM
 * @description debug抽空监听器 具体的观察者类,不需要抽象观察者
 **/
public class DebuggerWindowListener {

    public void closeDebugger(String name,String state){
        System.out.println("close debugger "+name+" state="+state);
    }
}

MainTest 测试类

/**
 * @author duanyimiao
 * @create 2018-10-04 5:20 PM
 * @description
 **/
public class MainTest {

    public static void main(String[] args) {
        AbstractNotifier notifier = new ConcreteNotifier();
        //如果toolBarListener和debuggerWindowListener都属于第三方类库中的类,那么无法让这些类实现抽象观察者接口,因此通过委托机制来实现,还有一个好处就是可以通知任意一个类中的任意一个方法
        ToolBarListener toolBarListener = new ToolBarListener();
        DebuggerWindowListener debuggerWindowListener = new DebuggerWindowListener();
        notifier.addListener("openToolBar",toolBarListener,"notify open");
        notifier.addListener("closeDebugger",debuggerWindowListener,"notify close","close");
        //在点击运行按钮,触发上面注册的事件
        notifier.notifyAfterRun();
    }
}

输出结果

open tool bar notify open
close debugger notify close state=close

猜你喜欢

转载自blog.csdn.net/u013830320/article/details/82943211