设计模式-观察者模式
1.观察者模式的定义
当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。
优点: 1、观察者和被观察者是抽象耦合的。 2、建立一套触发机制。
缺点: 1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
使用场景:
- 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
- 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
- 一个对象必须通知其他对象,而并不知道这些对象是谁。
- 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。
2.观察者模式的类图
- 主题接口:也就是一个抽象主题,抽象主题提供一个接口,可以增加和删除观察者角色,并通知所有观察者更新数据。
- 观察者接口:主要是提供一个update操作,在得到主题通知时会执行更新操作。
- 具体主题:具体主题实现了抽象主题的接口,同时可以定义一个ArrayList用来存放所有的观察者,在Notify函数中向所有登记过的观察者发出通知,即对每一个观察者执行update操作。
- 具体观察者:实现抽象观察者角色所需要的更新接口,一边使本身的状态与制图的状态相协调。
3.一个具体的例子
抽象主题接口
1 package observer_pattern; 2 /* 3 主题接口,主要有注册,删除,和通知三个功能 4 */ 5 public interface Subject { 6 7 public void registerObserver(Observer o); 8 9 public void removeObserver(Observer o); 10 11 public void notifyObserver(); 12 13 }
抽象观察者接口
1 package observer_pattern; 2 /** 3 * @Author:zhuchuanliang 4 * @Description:观察者需要实现这个接口来更新数据 5 * @Date:Created in:2018/5/22 0022 上午 11:22 6 * @Modified by: 7 */ 8 public interface Observer { 9 10 public void update(float temperature,float humidity,float pressure); 11 }
具体主题类
1 package observer_pattern; 2 3 import java.util.ArrayList; 4 5 /** 6 * @Author:zhuchuanliang 7 * @Description:具体主题类 8 * @Date:Created in:2018/5/22 0022 上午 11:26 9 * @Modified by: 10 */ 11 public class WeatherData implements Subject{ 12 public ArrayList observers; 13 private float temperature; 14 private float humidity; 15 private float pressure; 16 17 public WeatherData(){ 18 observers=new ArrayList(); 19 } 20 21 @Override 22 public void registerObserver(Observer o) { 23 observers.add(o); //添加观察者到一个ArrayList 24 } 25 26 @Override 27 public void removeObserver(Observer o) { 28 int i=observers.indexOf(o); 29 if(i>0){ 30 observers.remove(o); //将一个观察者从ArrayList中移除 31 } 32 33 } 34 35 @Override 36 public void notifyObserver() { 37 for(int i=0;i<observers.size();i++){ //通知所有观察者更新数据 38 Observer observer= (Observer) observers.get(i); 39 observer.update(temperature,humidity,pressure); //观察者更新自己的数据 40 } 41 42 } 43 44 public void measurementChanged(){ 45 notifyObserver(); //主题更新之后需要通知观察者 46 } 47 48 public void setMeasurements(float temperature,float humidity,float pressure){ //主题值得设置,这里的值变化了就意味着主题更新了 49 this.temperature=temperature; 50 this.humidity=humidity; 51 this.pressure=pressure; 52 measurementChanged(); 53 } 54 }
具体观察者
1 package observer_pattern; 2 3 /** 4 * @Author:zhuchuanliang 5 * @Description:具体观察者 6 * @Date:Created in:2018/5/22 0022 下午 14:00 7 * @Modified by: 8 */ 9 public class CurrentConditionsDisplay implements Observer{ 10 private float temperature; 11 private float humidity; 12 private Subject weatherData; 13 14 public CurrentConditionsDisplay(Subject weatherData){ //在创建观察者对象时就把该对象注册到主题中去 15 this.weatherData=weatherData; 16 weatherData.registerObserver(this); //注册当前对象 17 } 18 19 public void display() { 20 System.out.println("current conditions:"+temperature+"F degrees and"+humidity+"% humidity"); 21 } 22 23 @Override 24 public void update(float temperature, float humidity, float pressure) { //观察者的更新操作,即自己本身的值要与传过来的值保持一致 25 this.temperature=temperature; 26 this.humidity=humidity; 27 display(); //显示函数 28 } 29 }
测试
1 package observer_pattern; 2 3 /** 4 * @Author:zhuchuanliang 5 * @Description: 6 * @Date:Created in:2018/5/22 0022 下午 14:07 7 * @Modified by: 8 */ 9 public class Test { 10 public static void main(String[] args){ 11 WeatherData weatherData=new WeatherData(); 12 CurrentConditionsDisplay currentConditionsDisplay=new CurrentConditionsDisplay(weatherData); 13 weatherData.setMeasurements(80,65,30.4f); 14 weatherData.setMeasurements(82,70,31.4f); 15 weatherData.setMeasurements(79,90,29.3f); 16 } 17 }
运行结果
current conditions:80.0F degrees and65.0% humidity
current conditions:82.0F degrees and70.0% humidity
current conditions:79.0F degrees and90.0% humidity
参考文献:
- http://www.runoob.com/design-pattern/observer-pattern.html
- 《Head First设计模式》--中文版
- https://www.cnblogs.com/luohanguo/p/7825656.html