设计模式之观察者模式

一、什么是观察者模式

观察者模式,定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。

观察者模式,也叫发布-订阅模式、模型-视图模式,属于行为型结构模式。

二、观察者模式类图

设计模式之观察者模式插图

三、观察者模式角色

  • 抽象主题角色(Subject): 也叫抽象被观察者,是把所有观察者对象保存到一个集合里,抽象主题提供一个接口,包含增加和删除观察者对象,以及通知所有观察者的抽象方法。
  • 具体主题角色(ConcreteSubject):也叫具体被观察者,实现抽象主题接口中的通知方法,将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。
  • 抽象观察者角色(Observer):观察者的抽象类,是一个抽象类或接口,包含了更新自己的抽象方法,使得在得到主题更改通知时被调用。
  • 具体观察者角色(ConcreteObserver):具体观察者类,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。

四、观察者模式优缺点

1、优点

  1. 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系,满足依赖倒置原则。
  2. 被观察者发送通知,所有注册的观察者都会收到信息(类似于消息广播机制)。

2、缺点

  1. 如果观察者非常多的话,所有的观察者收到被观察者发送的通知会比较耗时,影响性能。
  2. 如果被观察者有循环依赖的话,有可能出现循环调用,导致系统崩溃。

五、观察者模式Demo示例

1、Demo需求

门户网站天气预报:新浪网站、网易网站、搜狐网站都有天气数据(温度、湿度、气压),在天气变化时通知各门户网站进行更新天气数据。

2、数据类定义

/**
  * 天气数据类
  */ 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、接口定义

/**
  * 抽象观察者角色:天气预报抽象观察者类
  */ public interface Observer {
 
     void update(WeatherInfo weatherInfo);

 }
/**
  * 抽象主题角色:被观察者类
  *
  */ 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、观察者定义

/**
  * 具体观察者角色:新浪观察者类
  */ public class SinaObserver implements Observer {
 
     @Override
     public void update(WeatherInfo weatherInfo) {
         System.out.println("<<<==新浪门户网站==>>>");
         System.out.println(weatherInfo);
         System.out.println("<<<==新浪门户网站==>>>");
     }
 }
 /**
  * 具体观察者角色:搜狐网站观察者类
  */ public class SohuObserver implements Observer {
     @Override
     public void update(WeatherInfo weatherInfo) {
         System.out.println("<<<==搜狐门户网站==>>>");
         System.out.println(weatherInfo);
         System.out.println("<<<==搜狐门户网站==>>>");
     }
 }
/**
  * 具体观察者角色:网易网站观察者类
  */ public class WangyiObserver implements Observer {
     public void update(WeatherInfo weatherInfo) {
         System.out.println("<<<==网易门户网站==>>>");
         System.out.println(weatherInfo);
         System.out.println("<<<==网易门户网站==>>>");
     }
 }

5、被观察者定义

/**
  * 具体主题角色:天气预报主题类(具体被观察者类)
  */ public class WeatherSubject extends Subject {
     private WeatherInfo weatherInfo;
 
     /**
      * 通知所有观察者对象
      *
      * @param weatherInfo
      */     @Override
     public void notify(WeatherInfo weatherInfo) {
         for (Observer observer : observers) {
             observer.update(weatherInfo);
         }
     }
 }

6、测试

 /**
  * 观察者模式客户端测试类
  * 
  */ 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"));
     }
 }
<<<==新浪门户网站==>>>
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'}
<<<==网易门户网站==>>>

发表评论