Java中的观察者模式
一. 观察者模式原理
观察者模式:定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,起相关的依赖对象都得到通知并自动更新。
就是说,观察者模式包含被观察者和观察者两类对象,一个被观察者可以被多个观察者观察,一旦被观察者的状态发生改变,所有的观察者都将得到通知。
观察者模式的结构中包含四种角色:
(1)主题(Subject):主题是一个接口,该接口规定了具体主题需要实现的方法,比如,添加、删除观察者以及通知观察者更新数据的方法。
(2)观察者(Observer):观察者是一个接口,该接口规定了具体观察者用来更新数据的方法。
(3)具体主题(ConcreteSubject):具体主题是实现主题接口类的一个实例,该实例包含有可以经常发生变化的数据。具体主题需使用一个集合,比如ArrayList,存放观察者的引用,以便数据变化时通知具体观察者。
(4)具体观察者(ConcreteObserver):具体观察者是实现观察者接口类的一个实例。具体观察者包含有可以存放具体主题引用的主题接口变量,以便具体观察者让具体主题将自己的引用添加到具体主题的集合中,使自己成为它的观察者,或让这个具体主题将自己从具体主题的集合中删除,使自己不再是它的观察者。
二. 观察者模式的具体应用
1.观察者
(1)观察者的抽象
WeatherObserver类是所有观察者的抽象,观察者可以通过实现它来创建观察者,被观察者的抽象就是观察者模式结构中的Observer角色。
1 package com.iluwatar.observer; 2 3 /** 4 * 5 * Observer interface. 6 * 7 */ 8 public interface WeatherObserver { 9 10 void update(WeatherType currentWeather); 11 12 }
(2)具体观察者
Oscr类和Hobbits类是作为具体的观察者,观察的是Weather类,接受Weather类的通知,具体观察者就是观察者模式中的ConcreteObserver角色。
1 /** 2 * 3 * Hobbits 4 * 5 */ 6 public class Hobbits implements WeatherObserver { 7 8 private static final Logger LOGGER = LoggerFactory.getLogger(Hobbits.class); 9 10 @Override 11 public void update(WeatherType currentWeather) { 12 switch (currentWeather) { 13 case COLD: 14 LOGGER.info("The hobbits are shivering in the cold weather."); 15 break; 16 case RAINY: 17 LOGGER.info("The hobbits look for cover from the rain."); 18 break; 19 case SUNNY: 20 LOGGER.info("The happy hobbits bade in the warm sun."); 21 break; 22 case WINDY: 23 LOGGER.info("The hobbits hold their hats tightly in the windy weather."); 24 break; 25 default: 26 break; 27 } 28 } 29 }
1 /** 2 * 3 * Orcs 4 * 5 */ 6 public class Orcs implements WeatherObserver { 7 8 private static final Logger LOGGER = LoggerFactory.getLogger(Orcs.class); 9 10 @Override 11 public void update(WeatherType currentWeather) { 12 switch (currentWeather) { 13 case COLD: 14 LOGGER.info("The orcs are freezing cold."); 15 break; 16 case RAINY: 17 LOGGER.info("The orcs are dripping wet."); 18 break; 19 case SUNNY: 20 LOGGER.info("The sun hurts the orcs' eyes."); 21 break; 22 case WINDY: 23 LOGGER.info("The orc smell almost vanishes in the wind."); 24 break; 25 default: 26 break; 27 } 28 } 29 }
2. 被观察者
这里是只考虑了唯一一个被观察者,没有考虑被观察者的多个是实现,所以直接实现了被观察者观察者,也就是将观察者模式中的Subject和ConcreteSubject角色合并了。
1 public class Weather { 2 3 private static final Logger LOGGER = LoggerFactory.getLogger(Weather.class); 4 5 private WeatherType currentWeather; 6 private List<WeatherObserver> observers; 7 8 public Weather() { 9 observers = new ArrayList<>(); 10 currentWeather = WeatherType.SUNNY; 11 } 12 13 public void addObserver(WeatherObserver obs) { 14 observers.add(obs); 15 } 16 17 public void removeObserver(WeatherObserver obs) { 18 observers.remove(obs); 19 } 20 21 /** 22 * Makes time pass for weather 23 */ 24 public void timePasses() { 25 WeatherType[] enumValues = WeatherType.values(); 26 currentWeather = enumValues[(currentWeather.ordinal() + 1) % enumValues.length]; 27 LOGGER.info("The weather changed to {}.", currentWeather); 28 notifyObservers(); 29 } 30 31 private void notifyObservers() { 32 for (WeatherObserver obs : observers) { 33 obs.update(currentWeather); 34 } 35 } 36 }
三. 观察者模式的优缺点
1. 优点
(1)观察者模式定义了稳定的消息更新传递机制,可以实现一对多的广播通信。
(2)观察者模式在被观察者和观察者之间建立的关系并不是很紧密,它们是不同的抽象,符合“低耦合”的系统设计理念
2. 缺点
(1)观察者模式建立的消息传递机制是低效的,如果建立了多个观察者,可能会影响消息传递的时间。
(2)观察者模式只会让观察者知道了被观察者发生了变化的结果,却不知道变化发生的过程。