观察者属于行为型模式的一种, 又叫发布-订阅模式. 若是一个对象的状态发生改变,依赖他的对象都将发生变化, 那么这种状况就适合使用观察者模式.html
它包含两个术语,主题(Subject),观察者(Observer), 主题管理一个观察者的列表, 并在状态发生变化时通知到他们.java
实现层面上, 主题定义了一个观察者列表并能够管理这个列表(将观察者注册进去和撤销注册的行为), 同时定义了通知到全部观察者的行为.api
Java类库有默认的观察者实现类Observer. 使用观察者模式的还有事件监听, RxJava等.多线程
定义对象之间的一对多依赖,当一个对象状态改变时,它的全部依赖都会收到通知而且自动更新状态。oracle
一. 定义抽象观察者异步
/** * 观察者抽象角色 */ public interface MyObserver { void update(Subject subject); }
二. 定义抽象主题this
/** * 主题抽象角色 */ public abstract class Subject { private ArrayList<MyObserver> list = new ArrayList<MyObserver>(); public Subject register(MyObserver observer){ if(!list.contains(observer)){ list.add(observer); } return this; } public Subject unRegister(MyObserver observer){ if(list.contains(observer)){ list.remove(observer); } return this; } public final void notifyObservers(){ for (MyObserver item:list) { item.update(this); } } /** * 具体状态的变动 */ abstract void change(); }
三. 定义具体主题spa
/** * 具体主题角色 */ @Data public class ConcreteSubject extends Subject { private String name; public void change() { this.setName("王多鱼"); super.notifyObservers(); } }
四. 定义观察者的实现, 分别定义两个不一样实现线程
public class UncleObserver implements MyObserver { public void update(Subject subject) { ConcreteSubject concreteSubject = (ConcreteSubject)subject; System.out.println("UncleObserver 知道了: "+concreteSubject.getName()); } } public class HentaiObserver implements MyObserver { public void update(Subject subject) { ConcreteSubject concreteSubject = (ConcreteSubject)subject; System.out.println("HentaiObserver 知道了: "+concreteSubject.getName()); } }
五. 调用, 首先注册观察者,而后调用主题的变动方法code
// 实例化主题后为其注册了两个观察者的实例, 并最终调用主题的变动方法触发通知行为 public static void main(String[] args) { new ConcreteSubject() .register(new UncleObserver()) .register(new HentaiObserver()) .change(); }
关键点: 定义通知到观察者的方法要注意, 若是有耗时严重的会阻塞其余观察者获得通知, 能够异步多线程实现; 避免循环引用;
观察者分推模式和拉模式, 推模式是指将主题的变动信息发送给观察者, 观察者能够用, 也能够不用. 拉模式则是将主题的引用发送给观察者, 观察者经过引用根据本身须要获取所需信息. 示例中使用的就是这种模式.
代码修改成推模式
// 观察者的方法接收具体信息 void update(String name); // 主题的通知方法作相应修改 public final void notifyObservers(){ for (MyObserver item:list) { item.update("王多鱼"); } }