文章内容
一、什么是观察者模式
观察者模式,定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。
观察者模式,也叫发布-订阅模式、模型-视图模式,属于行为型结构模式。
二、观察者模式类图

三、观察者模式角色
- 抽象主题角色(Subject): 也叫抽象被观察者,是把所有观察者对象保存到一个集合里,抽象主题提供一个接口,包含增加和删除观察者对象,以及通知所有观察者的抽象方法。
- 具体主题角色(ConcreteSubject):也叫具体被观察者,实现抽象主题接口中的通知方法,将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。
- 抽象观察者角色(Observer):观察者的抽象类,是一个抽象类或接口,包含了更新自己的抽象方法,使得在得到主题更改通知时被调用。
- 具体观察者角色(ConcreteObserver):具体观察者类,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。
四、观察者模式优缺点
1、优点
- 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系,满足依赖倒置原则。
- 被观察者发送通知,所有注册的观察者都会收到信息(类似于消息广播机制)。
2、缺点
- 如果观察者非常多的话,所有的观察者收到被观察者发送的通知会比较耗时,影响性能。
- 如果被观察者有循环依赖的话,有可能出现循环调用,导致系统崩溃。
五、观察者模式Demo示例
1、Demo需求
门户网站天气预报:新浪网站、网易网站、搜狐网站都有天气数据(温度、湿度、气压),在天气变化时通知各门户网站进行更新天气数据。
2、数据类定义
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | /** * 天气数据类 */ public class WeatherInfo { //溫度 private String temperature; //气压 private String pressure; //湿度 private String humidity; public WeatherInfo(String temperature, String pressure, String humidity) { this .temperature = temperature; this .pressure = pressure; this .humidity = humidity; } @Override public String toString() { return "WeatherInfo{" + "temperature='" + temperature + ' '' + ", pressure='" + pressure + ' '' + ", humidity='" + humidity + ' '' + '}' ; } } |
3、接口定义
1 2 3 4 5 6 7 | /** * 抽象观察者角色:天气预报抽象观察者类 */ public interface Observer { void update(WeatherInfo weatherInfo); } |
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | /** * 抽象主题角色:被观察者类 * */ public abstract class Subject { // 用于存放观察者对象的集合 protected List<Observer> observers = new ArrayList<>(); /** * 添加观察者到集合中 * @param observer */ public void add(Observer observer){ observers.add(observer); } /** * 从集合中删除观察者 * @param observer */ public void remove(Observer observer){ observers.remove(observer); } /** * 天气变化时,通知所有观察者 * 由子类实现 * @param weatherInfo */ public abstract void notify(WeatherInfo weatherInfo); } |
4、观察者定义
01 02 03 04 05 06 07 08 09 10 11 | /** * 具体观察者角色:新浪观察者类 */ public class SinaObserver implements Observer { @Override public void update(WeatherInfo weatherInfo) { System.out.println( "<<<==新浪门户网站==>>>" ); System.out.println(weatherInfo); System.out.println( "<<<==新浪门户网站==>>>" ); } } |
01 02 03 04 05 06 07 08 09 10 | /** * 具体观察者角色:搜狐网站观察者类 */ public class SohuObserver implements Observer { @Override public void update(WeatherInfo weatherInfo) { System.out.println( "<<<==搜狐门户网站==>>>" ); System.out.println(weatherInfo); System.out.println( "<<<==搜狐门户网站==>>>" ); } } |
1 2 3 4 5 6 7 8 9 | /** * 具体观察者角色:网易网站观察者类 */ public class WangyiObserver implements Observer { public void update(WeatherInfo weatherInfo) { System.out.println( "<<<==网易门户网站==>>>" ); System.out.println(weatherInfo); System.out.println( "<<<==网易门户网站==>>>" ); } } |
5、被观察者定义
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 | /** * 具体主题角色:天气预报主题类(具体被观察者类) */ public class WeatherSubject extends Subject { private WeatherInfo weatherInfo; /** * 通知所有观察者对象 * * @param weatherInfo */ @Override public void notify(WeatherInfo weatherInfo) { for (Observer observer : observers) { observer.update(weatherInfo); } } } |
6、测试
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 | /** * 观察者模式客户端测试类 * */ public class Client { public static void main(String[] args) { Observer sina = new SinaObserver(); Observer sohu = new SohuObserver(); Observer wangyi = new WangyiObserver(); Subject observable = new WeatherSubject(); observable.add(sina); observable.add(sohu); observable.add(wangyi); observable.notify( new WeatherInfo( "36.3" , "399.09" , "120.99" )); } } |
1 2 3 4 5 6 7 8 9 | <<<==新浪门户网站==>>> WeatherInfo{temperature='36.3', pressure='399.09', humidity='120.99'} <<<==新浪门户网站==>>> <<<==搜狐门户网站==>>> WeatherInfo{temperature='36.3', pressure='399.09', humidity='120.99'} <<<==搜狐门户网站==>>> <<<==网易门户网站==>>> WeatherInfo{temperature='36.3', pressure='399.09', humidity='120.99'} <<<==网易门户网站==>>> |