定义
观察者模式(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;}@Overridepublic 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 {@Subscribepublic 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、使用要得当,要避免循环调用。
本文介绍了观察者模式的概念,它用于在对象间建立一对多的依赖关系,当一个对象状态改变时,所有依赖者都会得到通知。通过一个简单的Java例子展示了如何创建事件和监听器,模拟鼠标事件的监听与回调。此外,还提及了使用Guava库实现观察者模式的简洁方式。文章最后讨论了该模式的优缺点,并提醒在实际应用中要避免过度依赖和循环调用。
9919

被折叠的 条评论
为什么被折叠?



