1、简介
观察者模式是对象的行为模式,又叫发布-订阅模式,它定义了一对多的依赖关系,让多个观察者同时监听一个主题对象,这个主题对象在发生变化时,会通知所有的观察者,使他们能自己更新自己
2、观察者模式类图
3、观察者模式涉及的角色
从上图可以看出,观察者模式涉及到以下四个角色
3.1、抽象主题角色:主题角色把所有观察者对象的引用保存在一个聚集里(比如vector 或者List)每个主题可以有任意数量的观察者,抽象主题提供接口,可以增加和删除观察者。主题角色也叫被观察者角色
3.2、具体主题角色:将有关状态存入具体观察者角色,在具体主题的内部发生变化时,给登记过的观察者发出通知
3.3、抽象观察者角色:为所有的具体观察者定义一个接口,在得到主题角色的通知是更新自己
3.4、具体观察者角色:存储与主题的状态,具体观察者角色实现抽象观察者角色所要求的接口,以便使自身的状态与主题的状态相协调
4、源代码
4.1、抽象观察者角色
package Observer; /** * ******************************************************** * @ClassName: Observer * @Description: 观察者角色 * ********************************************************** */ public interface Observer { //更新接口 public void update(float temperature); }
4.2、具体观察者角色
package Observer; /** * ******************************************************** * @ClassName: ConcreteObserver * @Description: 具体观察者角色 * ********************************************************** */ public class ConcreteObserver implements Observer{ private float temperature; private Subject subject; public ConcreteObserver( Subject subject) { this.subject = subject; this.subject.registerObserver(this); } public float getTemperature() { return temperature; } public void setTemperature(float temperature) { this.temperature = temperature; } @Override public void update(float temperature) { this.temperature = temperature; } }
4.3、抽象主题角色
package Observer; /** * ******************************************************** * @ClassName: Subject * @Description:抽象主题角色 * ********************************************************** */ public interface Subject { //调用这个方法登记一个新的观察者对象 public void registerObserver(Observer o); //调用这个方法删除一个已经登记过的观察者对象 public void removeObserver(Observer o); //通知所有登记过的观察者对象 public void notifyObservers(); }
4.4、具体主题角色
package Observer; import java.util.ArrayList; import java.util.List; /** * ******************************************************** * @ClassName: ConcreteSubject * @Description: 具体主题角色 * ********************************************************** */ public class ConcreteSubject implements Subject{ private List<Observer> observers =null;//观察者列表 private float temperature; public float getTemperature() { return temperature; } private void temperatureChanged() { this.notifyObservers(); } public void setTemperature(float temperature) { this.temperature = temperature; this.temperatureChanged(); } public ConcreteSubject() { observers = new ArrayList<Observer>(); } @Override public void registerObserver(Observer o) { observers.add(o); } @Override public void removeObserver(Observer o) { if (observers.indexOf(o) >= 0) { observers.remove(o); } } @Override public void notifyObservers() { for (final Observer o : observers) { o.update(temperature); } } }
4.5、测试客户端
package Observer; /** * ******************************************************** * @ClassName: Client * @Description: 观察者模式测试客户端 * ********************************************************** */ public class Client { public static void main(String[] args) { ConcreteSubject sb = new ConcreteSubject(); sb.setTemperature((float) 20.00); Observer o = new ConcreteObserver(sb); sb.setTemperature((float) 21.00); } }
5、总结
1、 对一个对象状态的更新,需要其他对象同步更新,而且其他对象的数量动态可变。
2、 对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节。
观察者模式的优点:
1、 Subject和Observer之间是松偶合的,分别可以各自独立改变。
2、 Subject在发送广播通知的时候,无须指定具体的Observer,Observer可以自己决定是否要订阅Subject的通知。
3、 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。
观察者模式的缺陷:
1、 松偶合导致代码关系不明显,有时可能难以理解。
2、 因为只是简单的遍历,如果一个Subject被大量Observer订阅的话,在广播通知的时候可能会有效率问题。