设计模式之观察者模式

一、什么是观察者模式

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

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

二、观察者模式类图

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

三、观察者模式角色

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

四、观察者模式优缺点

1、优点

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

2、缺点

  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'}
<<<==网易门户网站==>>>

发表评论

欢迎阅读『设计模式之观察者模式|Java、设计模式|Nick Tan-梓潼Blog』