设计模式之观察者模式
观察者模式:定义对象间的一种一对多的依赖关系,当一个对象状态发生改变时,所有依赖它的对象都得道通知并被自动更新。
别名:依赖、发布-订阅
这一模式的关键对象是目标和观察者,一个目标可以有任意数目的依赖它的观察者。一旦目标的状态发生改变,所有的观察者都得道通知。作为对通知的响应,
每个观察者都将查询目标以使其状态与目标状态同步。
什么情况下使用观察者模式?
1、当一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这二者封装在独立的对象中以使他们各自独立地改变和复用。
2、当一个对象的改变同时改变其他对象,而不知道具体有多少对象有待改变。
3、当一个对象必须通知其他对象,而它又不能假定其他对象是谁。
目标通知观察者的方式:
1、广播的方式:将通知广播给所有它的观察者,而不关系对方是否需要,观察者决定处理还是忽略这个通知。
观察者对消息的处理:
* 推模型:目标向观察者发送改变的所有信息,这些信息可能不是观察者对象全部都需要的,观察者根据收到的信息更新自己的数据。
* 拉模型:目标仅向观察者发送很少的信息,当观察者收到目标发送的信息后,还需要主动向目标获取它需要的信息。
更改管理器:
* 1、它维护目标到它的观察者之间的映射关系,这就不需要目标来维护队其观察者的引用。
* 2、它定义了一个特定的更新策略。
* 3、根据一个目标的请求,它更新所有依赖这个目标的观察者。
更改管理器通知观察者需要做异步处理,否则某个观察者存在阻塞操作,会导致通知其他观察者更新的操作被阻塞。
package observer; /** * 观察者接口,一个观察者可以观察(订阅)多个目标。 * 观察者更新数据可以有两种方式:推模型和拉模型。 * 推模型:目标向观察者发送改变的所有信息,这些信息可能不是观察者对象全部都需要的,观察者根据收到的信息更新自己的数据。 * 拉模型:目标仅向观察者发送很少的信息,当观察者收到目标发送的信息后,还需要主动向目标获取它需要的信息。 */ public interface Observer { void update(); }
package observer; public interface Subject { void attach(Observer observer); void detach(Observer observer); void notifyObserver(); }
package observer; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; /** * 这是一个更改管理器,它的作用有三点: * 1、它维护目标到它的观察者之间的映射关系,这就不需要目标来维护队其观察者的引用。 * 2、它定义了一个特定的更新策略。 * 3、根据一个目标的请求,它更新所有依赖这个目标的观察者。 * <p> * 更改管理器更新(注册和解除注册)动作可能会被多个目标同时出发,所以这两个操作应该是线程安全的。 */ public abstract class ChangeManager { //维护目标对象和它的观察者之间的映射关系,volatile保证多线程情况下映射关系的可见性。 protected volatile Map<Subject, Set<Observer>> map = new ConcurrentHashMap<>(); /** * 注册观察者和目标对象的映射关系 * * @param subject * @param observer */ synchronized void register(Subject subject, Observer observer) { /** * 更改管理器更新(注册和解除注册)动作可能会被多个目标同时出发,所以这两个操作应该是线程安全的。 * 虽然使用了ConcurrentHashMap,但更新目标对象的观察者列表不是线程安全的,所以这里对目标对象加锁。 * ConcurrentHashMap保证不同主题间的更改是线程安全的。 */ Set<Observer> subList = map.get(subject); if (subList == null || subList.size() == 0) { map.put(subject, Set.of(observer)); } else { subList.add(observer); map.put(subject, subList); } } /** * 解除目标对象与它的观察者关系映射 * * @param subject * @param observer */ synchronized void unRegister(Subject subject, Observer observer) { Set<Observer> subList = map.get(subject); if (subList != null || subList.size() > 0) { subList.remove(observer); map.put(subject, subList); } } /** * 通知观察者 */ abstract void notifyObserver(Subject subject); }