- 今天看了观察者模式,总体感觉就是,之前咱们会有这样一种思想,用个if语句,switch+case语句,while等来判断一下,当……就……。
- 但是举个例子,一个宝宝睡着了,如果按照之前的思路,就是让爸爸妈妈等一直蹲在宝宝床边,宝宝一哭,爸爸妈妈就要做出反应,
这样一来爸爸妈妈啥都干不了效率太低
。并且有很多孩子怎么办,花钱请保姆【加需求是不是违反了开闭原则啦】… - 可以使用观察者模式优化,用观察者模式后,我找一个大管家(名为注册中心)统一管理所有观察者(爸爸妈妈)和被观察者(宝宝),这会就灵活了,当宝宝(被观察者)一哭,注册中心立即给爸爸妈妈(观察者)发实时通知让赶紧来,当爸爸不想待家里管小孩了,只需给注册中心说一下,注册中心会取消他的观察者身份,他以后也不会收到实时通知;要是狗狗想加进来作为一个观察者,那么他只需要给注册中心说一声,注册中心以后就会给他也发实时通知。
- 但是举个例子,一个宝宝睡着了,如果按照之前的思路,就是让爸爸妈妈等一直蹲在宝宝床边,宝宝一哭,爸爸妈妈就要做出反应,
- 观察者模式
- 观察者模式
定义对象间的一种一对多的依赖关系
,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被完成业务的更新。观察者模式属于行为模式,一个对象(被观察者)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知
。它的主要成员就是观察者【观察者(observer):接受被观察者的状态变化通知,执行预先定义的业务】和被观察者【被观察者(Observerable):目标对象,状态发生变化时,将通知所有的观察者。】
。
- 观察者模式使用场景:
完成某件事情后,异步通知场景
。如,登陆成功,发个IM消息等等。 - 观察者模式实现的话得需要一个被观察者的类Observerable、一个或多个观察者Observer 、观察者的差异化实现【经典观察者模式封装:EventBus实战】
- 一个被观察者的类Observerable 和 多个观察者Observer
public class Observerable { private List<Observer> observers = new ArrayList<Observer>(); private int state; public int getState() { return state; } public void setState(int state) { notifyAllObservers(); } //添加观察者 public void addServer(Observer observer){ observers.add(observer); } //移除观察者 public void removeServer(Observer observer){ observers.remove(observer); } //通知 public void notifyAllObservers(int state){ if(state!=1){ System.out.println(“不是通知的状态”); return ; } for (Observer observer : observers) { observer.doEvent(); } } }
- 观察者的差异化实现
//观察者 interface Observer { void doEvent(); } //Im消息 IMMessageObserver implements Observer{ void doEvent(){ System.out.println("发送IM消息"); } } //手机短信 MobileNoObserver implements Observer{ void doEvent(){ System.out.println("发送短信消息"); } } //EmailNo EmailObserver implements Observer{ void doEvent(){ System.out.println("发送email消息"); } }
- 观察者模式有一个经典的封装好的:
Guava EventBus【它提供一套基于注解的事件总线,api可以灵活的使用】
- 被观察者角色:
//声明一个EventBusCenter类,它类似于被观察者那种角色Observerable。 public class EventBusCenter { private static EventBus eventBus = new EventBus(); private EventBusCenter() { } public static EventBus getInstance() { return eventBus; } //添加观察者 public static void register(Object obj) { eventBus.register(obj); } //移除观察者 public static void unregister(Object obj) { eventBus.unregister(obj); } //把消息推给观察者 public static void post(Object obj) { eventBus.post(obj); } }
- 观察者角色:EventListener
public class EventListener { @Subscribe //加了订阅,这里标记这个方法是事件处理方法 public void handle(NotifyEvent notifyEvent) { System.out.println("发送IM消息" + notifyEvent.getImNo()); System.out.println("发送短信消息" + notifyEvent.getMobileNo()); System.out.println("发送Email消息" + notifyEvent.getEmailNo()); } } //通知事件类 public class NotifyEvent { private String mobileNo; private String emailNo; private String imNo; public NotifyEvent(String mobileNo, String emailNo, String imNo) { this.mobileNo = mobileNo; this.emailNo = emailNo; this.imNo = imNo; } }
- 可以在main方法中使用
... public static void main(String[] args) { EventListener eventListener = new EventListener(); EventBusCenter.register(eventListener); EventBusCenter.post(new NotifyEvent("13372817283", "123@qq.com", "666")); } ...
- 被观察者角色:
- 一个被观察者的类Observerable 和 多个观察者Observer
- 除了上面举得例子,还有NIO 中的文件目录监听服务也使用到了观察者模式。
- NIO 中的文件目录监听服务基于 WatchService 接口和 Watchable 接口。WatchService 属于观察者,Watchable 属于被观察者。
- Watchable 接口定义了一个用于将对象注册到 WatchService(监控服务) 并绑定监听事件的方法 register
public interface Path extends Comparable<Path>, Iterable<Path>, Watchable{ } public interface Watchable { WatchKey register(WatchService watcher, WatchEvent.Kind<?>[] events, WatchEvent.Modifier... modifiers) throws IOException; }
- WatchService 用于监听文件目录的变化,同一个 WatchService 对象能够监听多个文件目录。
// 创建 WatchService 对象 WatchService watchService = FileSystems.getDefault().newWatchService(); // 初始化一个被监控文件夹的 Path 类: Path path = Paths.get("workingDirectory"); // 将这个 path 对象注册到 WatchService(监控服务) 中去 //register 方法返回 WatchKey 对象,通过WatchKey 对象可以获取事件的具体信息比如文件目录下是创建、删除还是修改了文件、创建、删除或者修改的文件的具体名称是什么 WatchKey watchKey = path.register( watchService, StandardWatchEventKinds...);//Path 类 register 方法的第二个参数 events (需要监听的事件)为可变长参数,也就是说我们可以同时监听多种事件:WatchKey register(WatchService watcher, WatchEvent.Kind<?>... events) throws IOException; //WatchService 内部是通过一个 daemon thread(守护线程)采用定期轮询的方式来检测文件的变化
- 常用的监听事件有 3 种:
- StandardWatchEventKinds.ENTRY_CREATE :文件创建
- StandardWatchEventKinds.ENTRY_DELETE : 文件删除
- StandardWatchEventKinds.ENTRY_MODIFY : 文件修改
- 常用的监听事件有 3 种:
- Watchable 接口定义了一个用于将对象注册到 WatchService(监控服务) 并绑定监听事件的方法 register
- Netty 中观察者模式的运用非常多,我们平时经常使用的ChannelFuture#addListener 接口就是观察者模式的实现。
- NIO 中的文件目录监听服务基于 WatchService 接口和 Watchable 接口。WatchService 属于观察者,Watchable 属于被观察者。
- 观察者模式
巨人的肩膀:
moon聊技术
设计模式之禅
head first设计模式
程序员田螺的设计模式文章
半码博客老师的关于手写一个简单的事件发布/订阅框架【首先创建一个事件类继承,所有的事件都继承该类、然后定义事件监听器接口EventListener、通过initEventMap()方法在项目启动后,利用反射注册所有的事件监听器,但是notifyListener()方法是串行执行,如果想要异步执行增加一个标记注解@AsyncExecute就行了、EventManager、一个发布事件的工具类EventPublisher、测试】