观察者模式 模式引入 问题描述 我们设想一个场景,假设公司几个同事日常喜欢工作摸鱼,有看 NBA 的,有炒股的,还有玩儿游戏的。但摸鱼肯定怕被自己领导或老板发现,怎么办呢?他们只好每隔几分钟就起来看看老板或者自己的领导有没有回来。这很不方便,想象一下,如果有几十个同事在摸鱼(这公司怕是要倒闭了),大家总不能跟赶集一样,隔几分钟就起来走几步吧。 此时,有人突拍大腿:为啥不整个吹哨人呢,比如前台小妹子?如果老板来了,她只需给我们发个微信消息通知一下就行了呀——有道理!先建个群把大家都拉进去,有领导来了就让前台小妹发消息。这下方便了,只要消息来了就知道是领导来了,赶紧采取行动。而且,如果这会儿突然不想摸鱼了,那把消息屏蔽了就行,明天又想摸鱼,把消息屏蔽取消就可以了。皆大欢喜。
我们设想一个场景,假设公司几个同事日常喜欢工作摸鱼,有看 NBA 的,有炒股的,还有玩儿游戏的。但摸鱼肯定怕被自己领导或老板发现,怎么办呢?他们只好每隔几分钟就起来看看老板或者自己的领导有没有回来。这很不方便,想象一下,如果有几十个同事在摸鱼(这公司怕是要倒闭了),大家总不能跟赶集一样,隔几分钟就起来走几步吧。
此时,有人突拍大腿:为啥不整个吹哨人呢,比如前台小妹子?如果老板来了,她只需给我们发个微信消息通知一下就行了呀——有道理!先建个群把大家都拉进去,有领导来了就让前台小妹发消息。这下方便了,只要消息来了就知道是领导来了,赶紧采取行动。而且,如果这会儿突然不想摸鱼了,那把消息屏蔽了就行,明天又想摸鱼,把消息屏蔽取消就可以了。皆大欢喜。
一般来说,将系统分割成一系列相互协作的类有个很不好的副作用,就是需要维护相关对象间的一致性。为了维护所需的一致性又不至于使各类紧密耦合,导致维护和扩展的不便,引入观察者模式。
观察者模式又叫发布-订阅(Publish/Subscribe)模式。它定义了一种一对多的依赖关系,多个观察者对象同时监听一个主题对象。当该主题对象的状态发生变化时,所有的观察者都会得到通知并自动更新。它描述了单个对象和一个或多个对象之间的发布-订阅关系。
我们用观察者模式重新分析开始的问题,针对领导的群就是 Subject,员工则是 Observer,一个 Subject 可以有多个 Observer,它不需要关心到底有哪些 Observer,Observer 之间也不需要知道彼此存在。当 Subject 的状态发生变化(即领导回来)时,所有的 Observer 都会得到通知,并更新自己的行为(努力工作)。
当然,反过来一个 Observer 可以订阅多个 Subject,任意一个 Subject 的状态发生变化,该 Observer 都会得到通知。这样就既解决了一致性问题,又不会过紧耦合。
共需要实现两个抽象类,以及它们对应的具体类。
Subject,定义 attach、detach 和 inform 方法。Observer,定义 update 方法。Boss。NBAObserver,StockObserver 等,每个类重写自己的 update 方法。另外需要注意,有两种方式可以实现通知:
我们下面用第一种方式实现。
Subject 类:
public interface Subject { void attach(Observer observer); void detach(Observer observer); void inform(); String getSubjectState(); void setSubjectState(String action); }
Observer 类:
public abstract class Observer { protected String name; protected Subject sub; public Observer(String name, Subject sub) { this.name = name; this.sub = sub; } public abstract void update(); }
ConcreteSubject 类:
public class Boss implements Subject { private List<Observer> observers = new ArrayList<>(); private String action; @Override public void attach(Observer observer) { observers.add(observer); } @Override public void detach(Observer observer) { observers.remove(observer); } @Override public void inform() { for(Observer o : observers){ o.update(); } } @Override public String getSubjectState() { return action; } @Override public void setSubjectState(String action) { this.action = action; } }
ConcreteObserver 类:
public class NBAObserver extends Observer { public NBAObserver(String name, Subject sub) { super(name, sub); } @Override public void update() { System.out.println(sub.getSubjectState() + " " + name + " 关闭NBA直播,继续工作!"); } } public class StockObserver extends Observer { public StockObserver(String name, Subject sub) { super(name, sub); } @Override public void update() { System.out.println(sub.getSubjectState() + " " + name + " 关闭股票行情,继续工作!"); } }
Main 方法:
public class Main { public static void main(String[] args) { Boss huhansan = new Boss(); Observer tongshi1 = new StockObserver("魏关姹", huhansan); Observer tongshi2 = new NBAObserver("易管查", huhansan); huhansan.attach(tongshi1); huhansan.attach(tongshi2); huhansan.detach(tongshi1); huhansan.setSubjectState("我胡汉三回来了!"); huhansan.inform(); } }
执行结果:
我胡汉三回来了! 易管查 关闭NBA直播,继续工作!

实际中的例子:批量自动更新。
观察者模式优点包括:
观察者模式缺点包括: