设计模式之观察者模式

定义

        观察者模式(Observer Pattern)定义了对象之间的一对多依赖,让多个观察者对象同时监听一个主体对象,当主体对象发生变化时,它的所有依赖者(观察者)都会收到通知并更新,属于行为型模式。观察者模式有时也叫做发布订阅模式。观察者模式主要用于在关联行为之间建立一套触发机制的场景。


适用场景

我们经常看到微信朋友圈的动态通知、邮件通知等

实例

我们来实现下java.awt.Event,简单的模拟下

创建Event类

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;    }    public Event setSource(Object source) {        this.source = source;        return this;    }    public Event setTime(long time) {        this.time = time;        return this;    }    public Object getSource() {        return source;    }    public Event setTrigger(String trigger) {        this.trigger = trigger;        return this;    }    public long getTime() {        return time;    }    public Object getTarget() {        return target;    }    public Method getCallback() {        return callback;    }    @Override    public String toString() {        return "Event{" + "\n" +                "\tsource=" + source.getClass() + ",\n" +                "\ttarget=" + target.getClass() + ",\n" +                "\tcallback=" + callback + ",\n" +                "\ttrigger='" + trigger + "',\n" +                "\ttime=" + time + "'\n" +                '}';    }}

创建 EventLisenter 类,监听器,我们可以认为他是观察者

public class EventLisenter {    //JDK底层的Lisenter通常也是这样来设计的    protected Map<String,Event> events = new HashMap<String,Event>();    //事件名称和一个目标对象来触发事件    public void addLisenter(String eventType,Object target){        try {            this.addLisenter(                    eventType,                    target,                    target.getClass().getMethod("on" + toUpperFirstCase(eventType),Event.class));        }catch (Exception e){            e.printStackTrace();        }    }    public void addLisenter(String eventType,Object target,Method callback){        //注册事件        events.put(eventType, new Event(target, callback));    }    //触发,只要有动作就触发    private void trigger(Event event) {        event.setSource(this);        event.setTime(System.currentTimeMillis());        try {            //发起回调            if(event.getCallback() != null){                //用反射调用它的回调函数                event.getCallback().invoke(event.getTarget(),event);            }        } catch (Exception e) {            e.printStackTrace();        }    }    //事件名称触发    protected void trigger(String trigger){        if(!this.events.containsKey(trigger)){return;}        trigger(this.events.get(trigger).setTrigger(trigger));    }    //逻辑处理的私有方法,首字母大写    private String toUpperFirstCase(String str){        char[] chars = str.toCharArray();        chars[0] -= 32;        return String.valueOf(chars);    }}

创建鼠标类型类

public interface MouseEventType {    //单击    String ON_CLICK = "click";    //双击    String ON_DOUBLE_CLICK = "doubleClick";    //弹起    String ON_UP = "up";    //按下    String ON_DOWN = "down";    //移动    String ON_MOVE = "move";    //滚动    String ON_WHEEL = "wheel";    //悬停    String ON_OVER = "over";    //失焦    String ON_BLUR = "blur";    //获焦    String ON_FOCUS = "focus";}

创建鼠标类

public class Mouse extends EventLisenter {    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 move(){        System.out.println("调用移动方法");        this.trigger(MouseEventType.ON_MOVE);    }    public void wheel(){        System.out.println("调用滚动方法");        this.trigger(MouseEventType.ON_WHEEL);    }    public void over(){        System.out.println("调用悬停方法");        this.trigger(MouseEventType.ON_OVER);    }    public void blur(){        System.out.println("调用获焦方法");        this.trigger(MouseEventType.ON_BLUR);    }    public void focus(){        System.out.println("调用失焦方法");        this.trigger(MouseEventType.ON_FOCUS);    }}

创建回调方法类

public class MouseEventCallback {    public void onClick(Event e){        System.out.println("===========触发鼠标单击事件==========" + "\n" + e);    }    public void onDoubleClick(Event e){        System.out.println("===========触发鼠标双击事件==========" + "\n" + e);    }    public void onUp(Event e){        System.out.println("===========触发鼠标弹起事件==========" + "\n" + e);    }    public void onDown(Event e){        System.out.println("===========触发鼠标按下事件==========" + "\n" + e);    }    public void onMove(Event e){        System.out.println("===========触发鼠标移动事件==========" + "\n" + e);    }    public void onWheel(Event e){        System.out.println("===========触发鼠标滚动事件==========" + "\n" + e);    }    public void onOver(Event e){        System.out.println("===========触发鼠标悬停事件==========" + "\n" + e);    }    public void onBlur(Event e){        System.out.println("===========触发鼠标失焦事件==========" + "\n" + e);    }    public void onFocus(Event e){        System.out.println("===========触发鼠标获焦事件==========" + "\n" + e);    }}

客户端测试类

public static void main(String[] args) {        MouseEventCallback callback = new MouseEventCallback();        Mouse mouse = new Mouse();        //@谁?@回调方法        mouse.addLisenter(MouseEventType.ON_CLICK,callback);        mouse.addLisenter(MouseEventType.ON_FOCUS,callback);        mouse.click();        mouse.focus();    }

当然了,我们可以用一个开发好的框架guava实现观察者模式,api非常简单,使用如下:

引入maven依赖

 <dependency>            <groupId>com.google.guava</groupId>            <artifactId>guava</artifactId>            <version>20.0</version>        </dependency>

创建侦听事件GuavaEvent

public class GuavaEvent {    @Subscribe    public void subscribe(String str){        System.out.println("执行subscribe方法,传入的参数是:" + str);    }}

测试类

public static void main(String[] args) {        //消息总线        EventBus eventBus = new EventBus();        GuavaEvent guavaEvent = new GuavaEvent();        eventBus.register(guavaEvent);        eventBus.post("Elvis");    }

 

 

优点

1、观察者和被观察者之间建立了一个抽象的耦合。 

2、观察者模式支持广播通信。

 

缺点

1、观察者之间有过多的细节依赖、提高时间消耗及程序的复杂度。 

2、使用要得当,要避免循环调用。​

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值