观察者模式 概念:当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。
本文以微信工作号的形式为例进行阐述观察者模式。
了解观察者模式首先需要了解观察者模式的概念,牵扯到4个概念 抽象主题: 抽象主题定义的是服务号接口 **具体主题:**具体主题主要是对抽象实体的实现 **抽象观察者:**抽象观察者定义的是订阅号接口 **具体观察者:**具体观察者是对抽象观察者的具体实现
抽象主题 微信中的服务号需要用户订阅才可以进行查看消息。故首先应该需要订阅服务号,此处体现为注册方法。 微信中的服务号还应该能够使用户在订阅的同时应该提供取消订阅的功能。此处体现为移除对于的订阅号。 此外服务号还需要通知订阅者查看订阅信息。此处体现为发送信息的方法。 抽象主题(服务号)
/** * 抽象主题:相当于微信公众号的服务号 */ public interface Subject { /** *服务号的提供注册服务 * @param observer 注册服务的观察者 */ public void registerObserver(Observer observer); /** * 服务号的提供取消订阅服务 * @param observer 移除订阅的观察者 */ public void removeObserver(Observer observer); /** * 服务号通知订阅号信息 */ public void notifyObserver(); }**抽象观察者:**就是相当于订阅号。订阅号作用就是获取订阅的信息。此处体现为更新用户获取的信息。
抽象观察者(订阅号)
/** *抽象观察者:相当于微信的订阅号 */
public interface Observer { /** * 获取服务号发送的信息 */ public void update(); }具体主题:(是对具体的抽象主题的具体实现) 注册需要记录对于的注册用户的信息,移除也需要移除对于的用户信息,二者都需要专门的存储用户信息,此处存储采用List集合的形式进行存储和移除,存储的此处为对像为观察者。 另外服务端需要向订阅号发送消息。此处体现为msg
/** * 微信公众号具体的实现 */ public class ServiceSubject implements Subject { //封装服务号发送的消息 private String msg; /** * 设置服务号要发送给订阅号的消息 * @param msg */ public void setMsg(String msg) { this.msg = msg; //调用通知发送给所有订阅者 notifyObserver(); } /** * 存储对应的观察者信息 */ private List<Observer>observers=new ArrayList<>(); /** * 存储对于的观察者(订阅号注册) * @param observer 注册服务的观察者 */ @Override public void registerObserver(Observer observer) { this.observers.add(observer); } /** * 去除对于的观察者(订阅号取消订阅) * @param observer 移除订阅的观察者 */ @Override public void removeObserver(Observer observer) { //在取消订阅的订阅号之前要先判断用户是否订阅 //observers.indexOf(observer)>0判断 返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1。 if (observers.indexOf(observer)>0){//注意此处返回的是索引,需要大于等于0 //根据观察者移除 this.observers.remove(observer); } } /** * 给所有的订阅者发送服务号消息 */ @Override public void notifyObserver() { for (Observer observer : observers) { observer.update(msg); } }**具体观察者:**对抽象观察者的具体实现。(此处的观察者是对订阅号的具体实现) 订阅号在订阅服务号的时候需要提供自己的订阅名。 其次,订阅号中要提供订阅的具体对象,便于订阅。 对以上二者的订阅进行私有化处理,在初始化的时候创建构造方法进行初始化操作。
/** * 服务号的订阅者:抽象观察者的具体实现 */ public class Subscription implements Observer{ /** * 对订阅者的名字封装 */ private String name; /** * 指定具体的订阅的服务号 */ private Subject subject; public Subscription(String name, Subject subject) { this.name = name; this.subject = subject; //调用注册服务对订阅号进行注册 subject.registerObserver(this);//此处的this表示对当前对象的引用。 } /** * 获取订阅号发送的订阅信息 * @param msg 获取服务号的消息内容 */ @Override public void update(String msg) { System.out.println(name+msg); } }测试代码
public class Test { public static void main(String[] args) { //创建服务号提供对外读物接口 ServiceSubject ss=new ServiceSubject(); //提供三个订阅号(构造方法的时候已经调用了注册方法。注册方法中调用了List方法存储订阅号信息) Observer observer1=new Subscription("Clearlove",ss); Observer observer2=new Subscription("Mikeo",ss); Observer observer3=new Subscription("Scout",ss); ss.setMsg("EDG"); } } public class Test { public static void main(String[] args) { //创建服务号提供对外读物接口 ServiceSubject ss=new ServiceSubject(); //提供三个订阅号(构造方法的时候已经调用了注册方法。注册方法中调用了List方法存储订阅号信息) Observer observer1=new Subscription("Clearlove",ss); Observer observer2=new Subscription("Mikeo",ss); Observer observer3=new Subscription("Scout",ss); //删除订阅者,同步更新订阅信息 ss.removeObserver(observer1); //服务号发生消息 ss.setMsg("该刷地下城了");}}总结:junit单元测试的时候,底层代码运用了观察者模式。 最后附上一张程序运行和理解图:供大家了解: