观察者模式

~信~仰~ 2019-02-27

java 事件 容器 观察者模式 string 设计模式 class void 主题 观察者

定义

定义对象的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

观察者模式是行为型模式之一。包含观察者模式包括观察者与被观察者两个基本元素,观察者会注册到被观察者中,而被观察者会保持和观察者的对应关系。

如果被观察的对象产生一些观察者感兴趣的变更,则观察者会得到通知从而去执行相关的操作。

常见的观察者模式

提到观察者模式,首先会想到前端中常用的事件机制。例如为dom元素绑定事件:

$(document).click(function (e) {
    console.dir(e);
});

这里的匿名function就是观察者,而document则是被观察者,.click(function)则是观察者注册的过程,此后document发生click事件时,被观察者则会收到通知,从而执行自己的逻辑console.dir(e)。

使用观察者模式

现在我们使用Java来模拟观察者模式。

先创建事件,包含事件源,通知目标,回调方法以及触发者等属性。

/**
 * 事件
 */
public class Event {

    private Object source; // 事件源
    private Object target; // 通知目标
    private Method callback; // 回调方法名称
    private String trigger; // 触发者
    private long time;

    public Event(Object target, Method callback) {
        this.target = target;
        this.callback = callback;
    }

    // 省略getter、setter
}

定义事件类型,此处定义添加、删除两种类型。

/**
 * 事件类型
 */
public enum EventType {
    /**
     * 添加
     */
    ADD,

    /**
     * 删除
     */
    RMOVE
}

定义抽象被观察者(主题),包含主题名称,保持与观察者引用映射的容器,以及事件触发的方法。

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 抽象主题
 * 定义主题通用的容器、事件注册及事件触发
 */
public class AbstractSubject {

    protected String name;
    protected Map<Enum,Event> eventMap = new HashMap<>(); // 注册容器

    public AbstractSubject() {}

    protected AbstractSubject(String name) {
        this.name = name;
    }

    /**
     * 事件注册
     * @param eventType
     * @param target
     * @param callback
     */
    public void addLisenter(Enum eventType, Object target, Method callback) {
        eventMap.put(eventType, new Event(target, callback));
    }

    /**
     * 事件触发
     * @param eventType
     */
    protected void trigger(Enum eventType) {
        Event event = this.eventMap.get(eventType);
        if(null == event) {
            return;
        }

        event.setSource(this);
        event.setTrigger(eventType.toString());
        event.setTime(System.currentTimeMillis());

        try {
            event.getCallback().invoke(event.getTarget(), event);
        } catch (Exception e1) {
            e1.printStackTrace();
        }
    }

    // 省略getter、setter
}

定义具体主题:

/**
 * 主题,被观察者
 */
public class Subject extends AbstractSubject {

    public Subject(String name) {
        super.name = name;
    }

    public void add() {
        trigger(EventType.ADD);
    }

    public void remove() {
        trigger(EventType.RMOVE);
    }
}

定义观察者,包含添加、删除事件对应的回调方法。

/**
 * 观察者
 */
public class Observer {

    public void onAdd(Event event) {
        System.out.println("收到" + event.getTrigger() + "的添加事件");
    }

    public void onRemove(Event event) {
        System.out.println("收到" + event.getTrigger() + "的删除事件");
    }
}

测试类:

/**
 * 测试类
 */
public class Test {

    public static void main(String[] args) throws NoSuchMethodException {
        // 观察者
        Observer observer = new Observer();

        // 观察者收到通知后执行的方法
        Method onAdd = Observer.class.getMethod("onAdd", Event.class);
        Method onRemove = Observer.class.getMethod("onRemove", Event.class);

        // 被观察者
        Subject subject = new Subject("目标1号");

        // 事件绑定
        subject.addLisenter(EventType.ADD, observer, onAdd);
        subject.addLisenter(EventType.RMOVE, observer, onRemove);

        // 被观察者触发事件
        subject.add();
        subject.remove();
    }
}

其中,得到观察者和主题对象后,进行观察者的注册,然后主题执行动作触发事件,这是整个流程。

如果需要做成主题和观察者一对多的映射,则将Event的target改成集合类型,如下:

private List<Object> targets; // 通知目标
登录 后评论
下一篇
我是你爱豆
1580人浏览
2019-08-22
相关推荐
设计模式- 观察者模式
576人浏览
2017-09-18 21:36:00
观察者设计模式
250人浏览
2017-08-25 10:51:51
java观察者模式
333人浏览
2016-10-31 22:01:00
0
0
0
354