您的位置:首页 > 其它

设计模式学习(二)-- 观察者模式 Observer Pattern

2015-03-19 09:41 405 查看
观察者模式:定义了对象之间的一对多依赖,这样当一个对象状态改变的时候,它的所有依赖者都会收到通知并自动更新。

设计原则:为了交互对象之间的松耦合设计而努力。

松耦合的设计让对象之间的依赖降到最低,这样便于建立更加有弹性的系统,应对变化。

实现观察者模式的方法不止一种,但是包含Subject和Observer接口的设计实现最常见。

主题只需要知道观察者实现了观察者接口Observer,不需要知道观察者的具体类是谁,做了什么。主题唯一依赖的是一个实现了观察者Observer接口的对象列表,可以随时增加,删除观察者,并方便地通知所有列表中的观察者。

观察者只需要持有一个主题的对象,用于注册成为主题的观察者,这样就可以接受到主题状态改变的通知。

观察者模式类图



主题是拥有数据或者状态的对象,观察者依赖主题来获取数据或者状态的改变。一个主题可以有多个观察者依赖它。主题负责在数据或者状态改变的时候,将改变通知所有依赖它的观察者。观察者必须注册具体主题,以便接受更新。

代码实现

/**
*
* @author Yves
*/
public interface Subject{
public void Register(Observer o);
public void Remove(Observer o);
public void NotifyObservers();
}


这是主题接口,对象使用此接口注册为观察者,或者把自己从观察者中删除。实现此接口的具体主题还必须实现NotifyObservers()方法用于在状态改变时通知所有的观察者。

class MySubject implements Subject {

private String name;
private int age;
//observers list
private ArrayList observers;

public MySubject() {
//create observers list in the Contruct method.
observers = new ArrayList();
}

@Override
public void Register(Observer o) {
observers.add(o);
}

@Override
public void Remove(Observer o) {
if (observers != null && !observers.isEmpty() && observers.contains(o)) {
observers.remove(o);
}
}

@Override
public void NotifyObservers() {
for (Object observer : observers) {
Observer ob = (Observer) observer;
ob.Update(name, age);
}
}

public void ChangeDate(String name, int age) {
this.SetName(name);
this.SetAge(age);
//notify all observers
this.NotifyObservers();
}

public void SetName(String name) {
this.name = name;
}

public void SetAge(int age) {
this.age = age;
}
}


具体主题类实现主题接口Subject,提供注册和删除观察者的方法,以及状态改变时通知所有观察者的方法。此处具体主题类维护一个ArrayList observers用来记录所有注册的观察者,以便实现注册、删除和通知观察者的方法。此外,具体主题类是拥有数据的对象,提供设置和获取这些数据的方法。ChangeDate(String name, int age)方法改变数据状态并且调用NotifyObservers()通知该主题维护的所有观察者。NotifyObservers()会调用每个观察者的Update()方法来实现数据状态改变的通知。

/**
*
* @author Yves
*/
public interface Observer{
public void Update(String name, int age);
}


所有潜在观察者必须实现观察者接口,这个接口只有一个Update()方法,当主题状态改变时它被调用。

class ObserverA implements Observer {

private String name;
private int age;
private MySubject mySubject;

public ObserverA(MySubject mySubject) {
this.mySubject = mySubject;
//Register this observer to the observer list of Subject object.
this.mySubject.Register(this);
}

@Override
public void Update(String name, int age) {
this.name = name;
this.age = age;

this.Display();
}

public void Display() {
System.out.println("User name is: " + name + ", User age is: " + age);
}

}


具体观察者实现观察者接口Observer,实现Update方法用于在主题的数据状态改变时更新这些数据状态。具体观察者必须注册主题,才能接收主题的更新通知。此处观察者持有一个具体主题的对象MySubject mySubject,在构造函数里面注册成为MySubject主题的观察者。

public class ObserverPattern {

public static void main(String args[]){
MySubject mys = new MySubject();
ObserverA oba = new ObserverA(mys);
//register an observer, THIS ACTIION is better done in the Observer class.
//mys.Register(oba);
//data change in MySubject, will notify all observers
mys.ChangeDate("Yves", 18);
//observers show the data
oba.Display();
}
}


注意:代码的实现不能依赖于观察者被通知的次序。因为一旦主题/观察者的实现改变了,通知的次序就会改变,依赖于某一特定实现的通知次序,是错误的。

Java API 内置观察者模式:java.util.Observable类和java.util.Observer为开发者接口提供了观察者模式。Observable类就是主题,具体的主题类需要继承Observable类。

由于Observable是一个类,所以具体主题就不能同时拥有Observable类和另一个超类的行为。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  观察者模式