1.8 观察者模式
田超凡
2019年11月1日
转载请注明原作者
1 观察者模式
在对象之间定义了一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象会收到通知并自动更新。
其实就是发布订阅模式,发布者发布信息,订阅者获取信息,订阅了就能收到信息,没订阅就收不到信息。
2 观察者模式实现原理
抽象主题角色(Abstract Subject):它把所有对观察者对象的引用保存在一个集合中,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。
具体主题角色(Subject):在集体主题的内部状态改变时,向所有登记过的观察者发出通知。
抽象观察者角色(Abstract Observer):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
具体观察者角色(Observer):实现抽象观察者角色所需要的更新接口,一边使本身的状态与制图的状态相协调。
主题角色负责发布消息,观察者角色订阅各类主题角色并接收消息。
抽象观察者角色
public interface ObServer { /** * 更新消息内容 * * @param message * @return */ public void update(String message);}
抽象主题角色
public interface AbstractSubject { /** * 添加obServer * * @param obServer */ void addObServer(ObServer obServer); /** * 移除obServer * * @param obServer */ void removeObServer(ObServer obServer); /** * 通知所有的notifyObServerAll * * @param message */ void notifyObServerAll(String message); /** * 设置更新内容 */ void setNtifyMessage(String message);}
具体主题角色
public class WeChatSubject implements AbstractSubject { /** * 存放所有的ObServer */ private List<ObServer> listObServer = new ArrayList<ObServer>(); /** * 更新的内容 */ private String message; public void addObServer(ObServer obServer) { listObServer.add(obServer); } public void removeObServer(ObServer obServer) { listObServer.remove(obServer); } public void notifyObServerAll(String message) { for (int i = 0; i < listObServer.size(); i++) { ObServer obServer = listObServer.get(i); obServer.update(message); } } public void setNtifyMessage(String message) { this.message = message; System.out.println("微信公众号设置message:" + message); notifyObServerAll(message); }}
具体观察者角色
public class UserObServer implements ObServer { /** * 订阅者用户名称 */ private String name; /** * 发送内容 */ private String message; public UserObServer(String name) { this.name = name; } public void update(String message) { this.message = message; read(); } public void read() { System.out.println(name + ",老师收到推送消息:" + message); }}
运行测试
// 1.注册主题AbstractSubject weChatSubject = new WeChatSubject();// 2.添加观察者 订阅主题weChatSubject.addObServer(new UserObServer("小薇"));weChatSubject.addObServer(new UserObServer("小敏"));// 3.设置发送消息weChatSubject.setNtifyMessage("下单成功");
(1). 自定义主题角色继承Observable类,Observable类封装了管理订阅的观察者相关操作,追踪所有的观察者,并通知他们。
(2). 自定义观察者角色实现Observer这个接口,重写接收发布信息的方法,可以获取对应的主题角色信息和发布的消息,它和我们之前写的类几乎一样。
自定义主题角色
public class MessageObServable extends Observable { @Override public void notifyObservers(Object arg) { // 1.改变数据 setChanged(); // 2.通知所有的观察者改变 super.notifyObservers(arg); }}
自定义观察者角色
public class EmailObServer implements Observer { public void update(Observable o, Object arg) { // 1.获取主题 MessageObServable messageObServable = (MessageObServable) o; System.out.println("发送邮件内容:" + arg); }}
public class SmsObServer implements Observer { public void update(Observable o, Object arg) { System.out.println("发送短信内容:" + arg); }}
运行监听开始
public class JdkObServer { public static void main(String[] args) { //1.创建主题 MessageObServable messageObServable = new MessageObServable(); // 2.添加订阅者 messageObServable.addObserver(new EmailObServer()); messageObServable.addObserver(new SmsObServer()); // 3.组装消息内容 JSONObject jsonObject = new JSONObject(); jsonObject.put("email", "xxxxxxxx@qq.com"); jsonObject.put("phone", "12315646465"); jsonObject.put("text", "恭喜您以1399.00元抢购成功."); messageObServable.notifyObservers(jsonObject.toJSONString()); }}
Spring实现事件通知的底层实现原理也是观察者模式封装的,只不过对外暴露了监听接口,主题角色的创建和观察者的订阅都交给Spring动态帮我们完成。
自定义主题角色继承ApplicationEvent,构造注入发布的消息
自定义观察者角色实现ApplicationListener<? extends ApplicationEvent>,重写onApplicationEvent(<? extends ApplicationEvent> obj)获取订阅的主题角色相关信息和接收到的发布信息。
public class OrderCreateEvent extends ApplicationEvent { private JSONObject jsonObject; public OrderCreateEvent(Object source, JSONObject jsonObject) { super(source); this.jsonObject = jsonObject; } public JSONObject getJsonObject() { return jsonObject; } public void setJsonObject(JSONObject jsonObject) { this.jsonObject = jsonObject; }}
@Componentpublic class EmailListener implements ApplicationListener<OrderCreateEvent> { @Override @Async public void onApplicationEvent(OrderCreateEvent event) { System.out.println(Thread.currentThread().getName()+"发送邮件内容:" + event.getJsonObject().toJSONString()); }}
@Componentpublic class SmsListener implements ApplicationListener<OrderCreateEvent> { @Override @Async public void onApplicationEvent(OrderCreateEvent event) { System.out.println(Thread.currentThread().getName() + "发送短信内容:" + event.getJsonObject().toJSONString()); }}
@RequestMapping("/addOrder")public String addOrder() { System.out.println("创建订单..."); // 3.组装消息内容 JSONObject jsonObject = new JSONObject(); jsonObject.put("email", "xxxxxxxxx@qq.com"); jsonObject.put("phone", "123456789"); jsonObject.put("text", "恭喜您以1399.00元下单成功."); OrderCreateEvent orderCreateEvent = new OrderCreateEvent(this, jsonObject); applicationContext.publishEvent(orderCreateEvent); return "success";}
补充说明:观察者模式(Observer)是行为型模式的一种,观察者模式支持消息发布和订阅,运用场景非常广泛,比如MQ消息队列中间件、Zookeeper节点和事件通知、Spring事件监听、安卓开发事件注册、微服务架构中的分布式配置中心数据同步等,对于被观察者而言,只需要根据不同业务类型定义不同的主题角色并提供容器存放订阅的观察者,开放对外接口能够发布消息通知订阅该主题角色的所有观察者。对于观察者而言,可以监听订阅的主题角色的变化并实时作出相应响应和更新数据,从而实现数据实时同步。并且观察者模式具有很强的扩展性,可以把主题角色和观察者角色各自使用抽象角色进行行为规范和约束,当业务量增加,需要新增主题角色和观察者角色时,只需要继承各自的抽象角色类(具体主题角色继承抽象主题角色,具体观察者角色继承抽象观察者角色),观察者角色也可以灵活订阅或者取消订阅相关的主题角色,消息发布和订阅机制实现了主题类角色和观察者类角色彻底解耦,不会影响之前的代码,提高代码的可扩展性和可维护性。
转载请注明原作者