观察者模式

认识观察者模式
1.首先我们来看看百度上对观察者模式的解释:

观察者模式(有时又被称为模型(Model)-视图(View)模式、源-收听者(Listener)模式或从属者模式)是软件设计模式的一种。在此种模式中,一个目标物件

管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。

2.百度的解释比较官方,那么我们就举个例子来理解观察者模式;

有一家报社,报社的业务就是出版报纸,如果我们向某家报社订阅报纸,只要他们有新的报纸出版,就会给我们送来一份。只要我们是报社的订户,我们就可以一直

收到出版社的报纸;那么当我们不再想看报纸时,我们可以取消订阅,报社就不会再给我们送报纸。不过只要报社一直存在,就会有读者向他们订阅报纸或者取消订

阅。而观察者模式就是这一个整体,观察者模式=出版社+订阅者。我们把出版社改称为"主题"(Subject),订阅者改称为"观察者"(Observer),这就是真正的观察者模

式!

定义观察者模式

观察者模式定义了一系列对象之间的一对多关系;观察者依赖于此模式,只要主题状态一有变化,观察者就会被通知。根据通知的风格,观察者可能因此新值而更新。

看完了这个定义,我们可能就会有疑问这和一对多的关系有什么关联,其间的依赖是如何产生的呢?

如果你也有这两个疑问的话,那么我们就来探讨探讨这两个问题。首先,利用观察者模式,主题是具有状态的对象,并且可以控制这些状态。也就是说,有"一个"具

有状态的主题。另一方面,观察者使用这些状态,虽然这些状态并不属于它们。有许多的观察者,依赖主题来告诉它们状态何时改变了。这就产生了一个关系:"一

个"主题对"多个"观察者的关系。接下来就解释依赖的产生了,因为主题是真正拥有数据的人,观察者是主题的依赖者,在数据变化时更新,这样比起许多对象控制同

一份数据来,可以得到更干净的OO设计。

松耦合的威力

我们在学习设计模式时会了解到一种"高内聚,低耦合"的思想。接下来我们就来看看,观察者模式的松耦合。

当两个对象之间松耦合,它们依然可以交互,但是不太清楚彼此的细节。观察者模式提供了一种对象设计,让主题和观察者之间松耦合。

为什么呢?

关于观察者的一切,主题只知道观察实现了某个接口(也就是Observer接口)。主题不需要知道观察者的具体类是谁,做了些什么操作。

任何时候我们都可以增加新的观察者。因为主题唯一依赖的东西是一个实现Observer接口的对象列表,所以我们可以随时增加观察者。事实上,在运行时我们可以

用新的观察者取代现有的观察者,主题不会受到任何影响。同样的,也可以在任何时候删除某些观察者。

有新类型出现时,主题的代码不需要修改。假如我们有个新的具体类需要当观察者,我们不需要为了兼容新类型而修改主题,所要做的事情就是在新的类里实现此观

察者接口,然后注册为观察者即可。主题不在乎别的,它只会发送通知给所有实现了观察者接口的对象。

我们可以独立地地复用主题或观察者。如果我们在其他地方需要使用主题或者观察者,可以轻易复用,因为二者并非紧耦合。改变主题或者观察者其中一方,并不会

影响另一方。因为两者是松耦合的,所以只要它们之间的接口仍然被遵守,我们就可以自由地改变它们。

松耦合的设计之所以能让我们建立有弹性的OO系统,能够应对变化,是因为对象之间的相互依赖降到了最低。

接下来我们用一个气象站的例子来实操一下观察者模式,首先我们的工作是实现measurementsChanged(),好让它更新目前的状况,气象统计,天气预报的显示布告板

//一旦气象站测量更新,此方法就会被调用
public void measurementsChanged(){ //我们要添加的代码 }
那么我们就先开始写接口吧

`

public interface Subject{  

public void registerObserver(Observer o);  

public void removeObserver(Observer o);  
//这两个方法都需要一个观察者作为变量,该观察者是用来注册或被删除的。  

public void notifyObserver();  
//当主题状态改变时,这个方法会被调用,以通知所有的观察者。   
}  

`

`

public interface Observer{
public void update(float temp,float humidity,float pressure);
//当气象观测值改变时,主题会把这些状态值当作方法的参数,传递给观察者.

}

`

`

public interface DisplayElement{
public void display();
//DisplayElement接口只包含了一个方法也就是display().
//当布告板需要显示时,调用此方法。

}

`
在WeatherData中实现主题接口

`

public class WeatherData implement Subject{
  //WeatherData 实现了Subject接口
  private ArrayList Observers;
  private float temperature;
  private float humidity;
  private float pressure;
  
  public WeatherData(){
    Observers = new ArrayList();
  }
  //我们加上一个ArrayList来记录观察者,此ArrayList是构造器中建立的

  public void registerObserver(Observer o){
    Observer.add(o);
    //注册观察者
  }
  
  public void removeObserver(Observe o){
    int i = Observer.indexOf(o);
    if(i>=0){
      Observer.remove(i);
      //删除观察者
    }
  }

  public void notifyObserver(){
    for(int i = 0;i<Observer.size();i++){
      Observer observer = (Observer)observer.get(i);
      Observer.update(temperature,humidity,pressure);
      //把状态告诉每一个观察者,因为每一个观察者都实现了update()
    }
  }

  public void measurementsChanged(){
    notifyObserver();
    //当气象站得到更新观测值,我们通知观察者。
  }

  public void setMeasurements(float temperature,float humidity,float pressure){
    this.temperature = temperature;
    this.humidity = humidity;
    this.pressure = pressure;
    measurementsChanged();
  }

  //WeatherData的其他方法

}  

`

** 布告板**
`

public class CurrentConditionDisplay implements Observer,DisplayElement{
  //实现了Observer接口,所以可以在WeatherData对象中获得改变,同时也实现了DisplayElement接口
  private float temperature;
  private float humidity;
  private Subject weatherData;

  public CurrentConditionDisplay(Subject weatherData){
    this.weatherData = weatherData;
    weatherData.registerObserver(this);
    //构造器需要weatherData对象,作为注册用
    }
  
  public void update(float temperature,float humidity,float pressure){
    this.temperature = temperature;
    this.humidity = humidity;
    display();
    当update()被调用时,我们把温度和湿度保存起来,然后调用display()
    }
  
public void display(){
  System.out.println("Current conditions:"+temperature+"F degrees and"+humidity+"% humidity");
   //显示方法
  }

 }

`
上面是我们自己写的观察者模式,在JAVA中其实有内置的观察者模式,不过java内置的观察者模式有着一些缺陷,它是一个"类"而不是"接口",因此限制了它的使用 和复用;同时它的设计违反了"多用组合,少用继承"的原则。所以我们有必要对观察者模式进行一定的学习和了解,以便于更加方便的使用观察者模式,甚至可以自己根据业务需要,实现一套观察者模式。

posted @ 2021-04-22 23:45  一只胖麻圆  阅读(336)  评论(0)    收藏  举报