您的位置:首页 > 其它

观察者模式理解

2014-04-06 11:46 302 查看

1. 概述

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

2. 解决的问题

  将一个系统分割成一个一些类相互协作的类有一个不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。观察者就是解决这类的耦合关系的。

3. 模式中的角色

  3.1 抽象主题(Subject):它把所有观察者对象的引用保存到一个聚集【使用集合】里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。

  3.2 具体主题(ConcreteSubject):将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。

  3.3 抽象观察者(Observer):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。

  3.4 具体观察者(ConcreteObserver):实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。


   

ConcreteSubject泛化了Subject接口,Subject接口持有Observer接口的引用【PS:隐含了1对多关系,一个Subject对应多个Observer,但是对应哪个具体的Observer是不知道的】

ConcreteObserver泛化了Observer接口,并持有Subject接口的引用用于初始化

1.Subject.java

public interface Subject {
public void registerObserver(Observer o);

public void removeObserver(Observer o);

public void notifyObservers();
}
2.Observer.java
public interface Observer {
public void update(float temp,float humidity,float pressure);

}

3.WeatherData.java【ConcreteSubject】
public class WeatherData implements Subject {

private ArrayList<Observer> observers;

private float humidity;

private float pressure;

private float temp;

public WeatherData()
{
observers=new ArrayList();
}

public float getHumidity() {
return humidity;
}

public float getPressure() {
return pressure;
}

public float getTemperature()
{
return temp;
}
@Override
public void notifyObservers() {
// TODO Auto-generated method stub
for(int i=0;i<observers.size();i++)
{
Observer observer=observers.get(i);
observer.update(temp, humidity, pressure);
}
}

@Override
public void registerObserver(Observer o) {
// TODO Auto-generated method stub
observers.add(o);
}

@Override
public void removeObserver(Observer o) {
// TODO Auto-generated method stub
int i=observers.indexOf(o);
observers.remove(i);
}

public void measurementsChanged()
{
notifyObservers();
}
public void SetMeasurements(float temp,float humidity,float pressure)
{
this.temp=temp;
this.humidity=humidity;
this.pressure=pressure;
measurementsChanged();
}

}


4.DisPlayElement.java【简单封装的一个接口】

public interface DisPlayElement {

public void display();
}

5.CurrentConditionsDisplay.java
public class CurrentConditionsDisplay implements Observer, DisPlayElement {
private float humidity;

private float pressure;

private float temp;

private Subject weatherData;

public CurrentConditionsDisplay(Subject weatherData)
{
this.weatherData=weatherData;
weatherData.registerObserver(this);
}

@Override
public void update(float temp, float humidity, float pressure) {
// TODO Auto-generated method stub
this.temp=temp;
this.humidity=humidity;
this.pressure=pressure;
display();

}

@Override
public void display() {
// TODO Auto-generated method stub

System.out.println("温度:  "+temp+"   湿度:  "+humidity+"   气压:  "+pressure);
}

}

6.Test.java

public class Test {

/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub

WeatherData weatherdata=new WeatherData();
CurrentConditionsDisplay currentDisplay=new CurrentConditionsDisplay(weatherdata);
weatherdata.SetMeasurements(90, 90, 91);
weatherdata.SetMeasurements(91, 91, 90);
weatherdata.SetMeasurements(92, 92, 91);
}

}

三、观察者模式的优点 

具体主题和具体观察者是松耦合关系。由于主题(Subject)接口仅仅依赖于观察者(Observer)接口【ps:这里的类间关系并不持久,或者说不说绑定的】,因此具体主题只是知道它的观察者是实现观察者(Observer)接口的某个类的实例,但不需要知道具体是哪个类。同样,由于观察者仅仅依赖于主题(Subject)接口,因此具体观察者只是知道它依赖的主题是实现主题(subject)接口的某个类的实例,但不需要知道具体是哪个类。
【依赖接口不依赖具体类】
观察模式满足“开-闭原则”。主题(Subject)接口仅仅依赖于观察者(Observer)接口,这样,我们就可以让创建具体主题的类也仅仅是依赖于观察者(Observer)接口,因此如果增加新的实现观察者(Observer)接口的类,不必修改创建具体主题的类的代码。同样,创建具体观察者的类仅仅依赖于主题(Observer)接口,如果增加新的实现主题(Subject)接口的类,也不必修改创建具体观察者类的代码。

关联和依赖的区别:

从类之间关系的强弱程度来分,关联表示类之间的很强的关系;依赖表示类之间的较弱的关系;
从类之间关系的时间角度来分,关联表示类之间的“持久”关系,这种关系一般表示一种重要的业务之间的关系,需要保存的,或者说需要“持久化”的,或者说需要保存到数据库中的。比如学生管理系统中的Student类和Class(班级)类,一个Student对象属于哪个Class是一个重要的业务关系,如果这种关系不保存,系统就无法管理。另外,依赖表示类之间的是一种“临时、短暂”关系,这种关系是不需要保存的,比如Student类和StuEditScreen(学生登录界面)类之间就是一种依赖关系,StuEditScreen类依赖Student类,依赖Student对象的信息来显示编辑学生信息。
设计类之间的关系是遵循的原则:首先判断类之间是否是一种“关联”关系,若不是再判断是否是“依赖关系”,一般情况下若不是关联,就是依赖关系
依赖一般情况下是以下几种情况之一:a、ClassA中某个方法的参数类型是ClassB;这种情况成为耦合;b、ClassA中某个方法的参数类型是ClassB的一个属性;这种情况成为紧耦合;c、ClassA中某个方法的实现实例化ClassB;d、ClassA中某个方法的返回值的类型是ClassB;如果出现了上述四种情况之一,两个类很有可能就是“依赖”关系。

依赖关系(Dependency):是类与类之间的连接,依赖总是单向的。依赖关系代表一个类依赖于另一个类的定义。下面的例子中class A 依赖与class B、C、D。

java 代码

public class A{
public B getB(C c, D d){
E e = new E();
B b = new B(c, d, e);
}


四.常见应用

java.util.Observer,Observable

文档说明:

An observable object can have one or more observers. An observer may be any object that implements interface
Observer. After an observable instance changes, an application calling the
Observable
's
notifyObservers
method causes all of its observers to be notified of the change by a call to their
update
method. 

1.Observer.java

public interface Observer {
/**
* This method is called whenever the observed object is changed. An
* application calls an <tt>Observable</tt> object's
* <code>notifyObservers</code> method to have all the object's
* observers notified of the change.
*
* @param   o     the observable object.
* @param   arg   an argument passed to the <code>notifyObservers</code>
*                 method.
*/
void update(Observable o, Object arg);
}
         2.Observable.java
public class Observable {
private boolean changed = false;
private Vector obs;

public Observable() {
obs = new Vector();
}

public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}

public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}

public void notifyObservers() {
notifyObservers(null);
}

public void notifyObservers(Object arg) {

Object[] arrLocal;

synchronized (this) {

if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}

for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}

public synchronized void deleteObservers() {
obs.removeAllElements();
}

protected synchronized void setChanged() {
changed = true;
}

protected synchronized void clearChanged() {
changed = false;
}

public synchronized boolean hasChanged() {
return changed;
}

public synchronized int countObservers() {
return obs.size();
}
}

JDK为我们提供了强大的实现,为我们减去了很多的工作量,不过这是依赖类的却不是接口。

AWT ,SWing中的原理大概也是如此的

5. 模式总结

  5.1 优点

    5.1.1 观察者模式解除了主题和具体观察者的耦合,让耦合的双方都依赖于抽象,而不是依赖具体。从而使得各自的变化都不会影响另一边的变化。

  5.2 缺点

    5.2.1 依赖关系并未完全解除,抽象通知者依旧依赖抽象的观察者。

  5.3 适用场景

    5.3.1 当一个对象的改变需要给变其它对象时,而且它不知道具体有多少个对象有待改变时。

    5.3.2 一个抽象某型有两个方面,当其中一个方面依赖于另一个方面,这时用观察者模式可以将这两者封装在独立的对象中使它们各自独立地改变和复用。

                     有问题,请指导促进互相学习!

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: