观察者模式总结

观察者模式

观察者模式还有一个名字叫发布-订阅模式,我们熟悉的消息队列如ActiveMQ,就是采用的这种设计模式,总的来说观察者模式主要难理解的地方有两个,一个是发布者对一个或多个观察者的管理,另一个就是实现消息发布者和订阅者之间的解耦。

比较简单的实例已经有相关博客总结的非常OK了,如这篇:观察者模式简单实例,该片博客中的实例虽然简单,但是却非常具有代表性,能较好的解释观察模式的几个概念。下面在这篇博客的基础上实现其实例,并对实例做一些简单的改动

上类图:


IPublish和ICustomer代码:

public interface IPublisher {

    public void registerObserver(ICustomer o);
    public void removeObserver(ICustomer o);
    public void notifyObserver();

}
public interface ICustomer {

    public void receiveMessage(String message);

}

Publish和Customer代码:

public class Publisher implements IPublisher {

    private List<ICustomer> observers;
    private String message;

    public Publisher(List<ICustomer> observers){
        this.observers = observers;
    }

    @Override
    public void registerObserver(ICustomer o) {
        observers.add(o);
    }

    @Override
    public void removeObserver(ICustomer o) {
        if(!observers.isEmpty()){
            observers.remove(o);
        }
    }


    @Override
    public void notifyObserver() {
        for(ICustomer o:this.observers){
            o.receiveMessage(message);
        }
    }

    /**
     * 设置了消息立即通知观察者
     * @param message
     */
    public void setInformation(String message){
        this.message = message;
        System.out.println("公众号更新消息如下:"+message);

        //通知观察者
        notifyObserver();
    }
}
public class Customer implements ICustomer{

    private String name;
    private String message;

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

    @Override
    public void receiveMessage(String message) {
        this.message = message;
        read();
    }

    public void read(){
        System.out.println(name+":收到推送消息:"+message);
    }
}

测试实例:

public class ClientTest {

    public static void main(String[] args) {
        //这里需要模拟一个发布者,多个订阅者

        //消息订阅者
        ICustomer cus01  = new Customer("body01");
        ICustomer cus02  = new Customer("body02");
        ICustomer cus03  = new Customer("body03");

        //消息发布者
        List<ICustomer> observers = new ArrayList<ICustomer>();
        observers.add(cus01);
        observers.add(cus02);
        observers.add(cus03);

        Publisher subscribe = new Publisher(observers);
        //更新了消息之后,会自动通知消费者
        subscribe.setInformation("message01 ---这是人性的扭曲还是道德的沦丧");
        System.out.println("cus01 取消关注公众号");
        observers.remove(cus01);
        subscribe.setInformation("message02 ---震惊,一群男女光天化日下尽然干这事......");
    }

}

运行结果:


一个比较简单的实例,但是却将观察者模式的相关对象展示的比较清晰,回到文章的开头,观察模式会有两个难理解的地方,一个是针对多个订阅者的维护,上述实例是通过在发布者对象中维护一个list来完成对多个订阅者的维护,针对解耦,上述实例是定义了两个接口,消息发布接口和消息订阅者接口,两者都可以自动扩展自己的对象——如果用于需要关注另一个公众号,只需要在加一个公众号类实现消息发布接口即可。

其实见到观察者模式,还有一个不得不提到的就是Listener(监听器),这在spring中也大量用到,这里需要进一步理解这个概念,如果提到监听器,第一反应就想到了之前C/S模式下的各种控件监听事件的编写,所以这里就利用一个简单的鼠标事件例子来进一步解释观察者模式

类图:


这个实例中Mouse就是其实就类似消息的发布者,点击了鼠标,相当于发出了消息,Event会根据事件类型去调用相应的处理方式,就是MouseEventCallBack,所以这里的MouseEventCallBack就相当于是订阅者,而其中的EventListener相当于是消息发布者维护消息订阅者的一张表而已。根据不同的事件去调动不同的Event对象,Event对象根据callback方法去调用MouseEventCallback中相应的方法。各个类的代码如下:

Mouse

public class Mouse extends EventListener{

    public void click(){
        System.out.println("鼠标单击");
        this.trigger(MouseEventType.ON_CLICK);
    }

    public void doubleClick(){
        System.out.println("鼠标双击");
        this.trigger(MouseEventType.ON_DOUBLE_CLICK);
    }

    public void up(){
        System.out.println("鼠标弹起");
        this.trigger(MouseEventType.ON_UP);
    }

    public void down(){
        System.out.println("鼠标按下");
        this.trigger(MouseEventType.ON_DOWN);
    }

    public void wheel(){
        System.out.println("鼠标滚动");
        this.trigger(MouseEventType.ON_WHEEL);
    }

    public void hover(){
        System.out.println("鼠标悬停");
        this.trigger(MouseEventType.ON_HOVER);
    }
}

MouseEventCallback

public class MouseEventCallback {

    public void onClick(Event e){
        System.out.println("=================触发了鼠标单击事件=================\n");
    }

    public void onDoubleClick(Event e){
        System.out.println("=================触发了鼠标双击事件=================\n");
    }

    public void onUp(Event e){
        System.out.println("=================触发了鼠标弹起事件=================\n");
    }

    public void onDown(Event e){
        System.out.println("=================触发了鼠标下压事件=================\n");
    }

    public void onWheel(Event e){
        System.out.println("=================触发了鼠标滚动事件=================\n");
    }

    public void onHover(Event e){
        System.out.println("=================触发了鼠标悬停事件=================\n");
    }

    public void onMove(Event e){
        System.out.println("=================触发了鼠标移动事件=================\n");
    }

}

EventListener

public class EventListener {

    protected Map<Enum,Event> events = new HashMap<Enum,Event>();

    public void addListener(Enum eventType,Object target,Method callback){
        //注册事件,待会儿会用反射来调用方法
        events.put(eventType,new Event(target,callback));
    }

    private void trigger(Event event){
        event.setSource(this);
        event.setTirggerTime(System.currentTimeMillis());

        try {
            //invoke的参数,第一个是object对象,第二个是方法
            event.getCallback().invoke(event.getTarget(),event);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    protected void trigger(Enum call){
        if(!this.events.containsKey(call)){
            return;
        }
        trigger(this.events.get(call).setTrigger(call.toString()));
    }
}

Event

public class Event {

    //事件源
    private Object source;
    //通知目标
    private Object target;
    //回调
    private Method callback;
    //触发器
    private String trigger;
    //时间
    private long tirggerTime;

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

    public Object getSource() {
        return source;
    }

    public Object getTarget() {
        return target;
    }

    public Method getCallback() {
        return callback;
    }

    public void  setCallback(Method callback) {
        this.callback = callback;
    }

    Event setSource(Object source) {
        this.source = source;
        return this;
    }

    protected void setTirggerTime(long tirggerTime) {
        this.tirggerTime = tirggerTime;
    }

    Event setTrigger(String trigger) {
        this.trigger = trigger;
        return this;
    }

    public String getTrigger() {
        return trigger;
    }

    public long getTirggerTime() {
        return tirggerTime;
    }



    @Override
    public String toString() {
        return "Event{" +
                "\t source=" + source +
                "\t, target=" + target +
                "\t, callback=" + callback +
                "\t, trigger='" + trigger + '\'' +
                '}';
    }
}

MouseEventType——事件类型枚举

public enum MouseEventType {
    ON_CLICK,
    ON_DOUBLE_CLICK,
    ON_UP,
    ON_DOWN,
    ON_WHEEL,
    ON_MOVE,
    ON_HOVER;
}

测试类:

public class MouseTest {

    public static void main(String[] args) {

        try {
            //鼠标对象
            Mouse mouse = new Mouse();

            //鼠标事件的回调函数对象
            MouseEventCallback callback = new MouseEventCallback();
            //获得回调对象中的onClick事件处理函数
            Method onClick = callback.getClass().getMethod("onClick",Event.class);

            //加入监听绑定事件
            System.out.println(onClick.toString());
            mouse.addListener(MouseEventType.ON_CLICK,callback,onClick);

            Method onDoubleClick = callback.getClass().getMethod("onDoubleClick",Event.class);
            mouse.addListener(MouseEventType.ON_DOUBLE_CLICK,callback,onDoubleClick);

            //人为调用鼠标事件
            mouse.click();
            mouse.doubleClick();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

运行结果:


说明:Mouse类继承了EventListener似乎就是表示鼠标类是一个消息发布者而已,EventListener的任务就是维护不同的事件类型,Event中的一些set方法为了简单,直接返回了this对象,这个有点不规范。EventListener中的一个trigger中是利用反射去调用的指定的响应函数,整个例子需要结合类图才能有更好的理解。

在一定程度上上述简单的实例好像也可以用动态代理来实现,确实可以,某一种层度上MouseCallback就是mouse的增强,这个理解也算是正确吧,但是这里也是为了说明观察者模式而举得一个常用的实例。

猜你喜欢

转载自blog.csdn.net/liman65727/article/details/79760534