觀察者模式
1.定義
- 觀察者模式定義了一種一對多的依賴關系,讓多個觀察者對象同時監聽某一個主題對象。這個主題對象在狀態發生變化時,會通知所有的觀察者對象,使它們能夠自動更新自己。
- 觀察者模式又叫做發布-訂閱模式、模型-視圖模式,源-監聽器模式。
package cn.sun.code.fourteen;
import java.util.ArrayList;
/**
* 主題對象或抽象通知者,一般用一個抽象類或一個接口實現。
* 它把所有對觀察者對象的引用保存在一個聚集里,每個主題都可以用任何數量的觀察者。
* 抽象主題提供一個接口,可以增加和刪除觀察者對象。
*/
abstract class Subject {
private ArrayList<Observer> observerArrayList = new ArrayList<Observer>();
// 增加觀察者
public void attach(Observer observer) {
observerArrayList.add(observer);
}
// 移除觀察者
public void deatch(Observer observer) {
observerArrayList.remove(observer);
}
// 通知
public void notifyObserver() {
for (Observer observer : observerArrayList) {
observer.update();
}
}
}
package cn.sun.code.fourteen;
/**
* 具體主題或具體通知者,將有關狀態存入具體觀察者對象;在具體主題的內部狀態改變時,
* 給所有登記過的通知者發出通知。
* 具體主題角色通常用一個具體子類實現。
*/
public class ConcreteSubject extends Subject {
private String subjectStatus;
public String getSubjectStatus() {
return subjectStatus;
}
public void setSubjectStatus(String subjectStatus) {
this.subjectStatus = subjectStatus;
}
}
package cn.sun.code.fourteen;
/**
* Observer類,抽象觀察者,為所有的具體觀察者定義一個接口,在得到主題的通知時更新自己。
* 這個接口叫做更新接口。抽象觀察者一般用一個抽象類或者一個接口實現。
* 更新接口通常包含一個update方法,這個方法叫做更新方法。
*/
abstract class Observer {
public abstract void update();
}
package cn.sun.code.fourteen;
/**
* 具體觀察者,實現抽象觀察者角色所要求的更新接口,以便使本身的狀態與主題的狀態相協調。
* 具體觀察者角色可以保存一個角色可以保存一個指向具體主題對象的應用。
* 具體觀察者角色通常用一個具體子類實現。
*/
public class ConcreteObserver extends Observer {
private String name;
private String observerStatus;
private ConcreteSubject subject;
public ConcreteObserver(String name, ConcreteSubject subject) {
this.name = name;
this.subject = subject;
}
@Override
public void update() {
observerStatus = subject.getSubjectStatus();
System.out.println("觀察者" + name + "的收到木葉新狀態是:" + observerStatus);
}
}
package cn.sun.code.fourteen;
/**
* 客戶端代碼
*/
public class Client {
public static void main(String[] args) {
ConcreteSubject subject = new ConcreteSubject();
subject.attach(new ConcreteObserver("霧之國",subject));
subject.attach(new ConcreteObserver("砂之國",subject));
subject.attach(new ConcreteObserver("土之國",subject));
subject.setSubjectStatus("被佩恩攻打");
subject.notifyObserver();
}
}
// 觀察者霧之國的收到木葉新狀態是:被佩恩攻打
// 觀察者砂之國的收到木葉新狀態是:被佩恩攻打
// 觀察者土之國的收到木葉新狀態是:被佩恩攻打
2.為什么使用觀察者模式
- 當一個對象的改變需要同時改變其他對象,而且它不知道具體有多少對象有待改變時,應該考慮使用觀察者模式。
- 觀察者模式所做的工作其實就是解耦。讓耦合的雙方都依賴於抽象而不是依賴於具體。從而使得各自的變化都不會影響另一邊的變化。
3.觀察者模式在Java中的應用
- jdk是直接支持觀察者模式的,就是
java.util.Observer
這個接口:
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);
}
- 這是觀察者的接口,定義的觀察者只需要實現這個接口就可以了。
update()方法
,被觀察者的notifyObservers()
方法就會調用這個方法。
public class Observable {
private boolean changed = false;
private Vector obs;
/** Construct an Observable with zero Observers. */
public Observable() {
obs = new Vector();
}
/**
* Adds an observer to the set of observers for this object, provided
* that it is not the same as some observer already in the set.
* The order in which notifications will be delivered to multiple
* observers is not specified. See the class comment.
*
* @param o an observer to be added.
* @throws NullPointerException if the parameter o is null.
*/
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
...
}
- 這是被觀察者的父類,也就是主題對象。這是一個線程安全的類,是基於Vector實現的。主題對象中有這些方法對觀察者進行操作:
方法 |
作用 |
addObserver(Observer o) |
向觀察者集合中添加觀察者 |
clearChanged()、hasChanged()、setChanged() |
這三個方法算是一對,用它們來標記主題對象的狀態是否改變 |
countObservers() |
返回觀察者對象的數目 |
deleteObserver(Observer o) |
刪除某個觀察者 |
deleteObservers() |
清楚觀察者列表 |
notifyObservers()、notifyObservers(Object arg) |
若本對象有變化,則通知所有登記的觀察者,調用update() 方法 |
使用jdk支持的觀察者模式示例
package cn.sun.code.fourteen;
import java.util.Observable;
import java.util.Observer;
public class MyTomcat extends Observable {
private String status = "";
public String getStatus() {
return status;
}
public MyTomcat(Observer o) {
addObserver(o);
}
public void setStatus(String status) {
if (!this.status.equals(status)) {
this.status = status;
setChanged();
}
notifyObservers();
}
}
package cn.sun.code.fourteen;
import java.util.Observable;
import java.util.Observer;
/**
* 自定義觀察者
*/
public class MySpring implements Observer {
String status = "";
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
@Override
public void update(Observable o, Object arg) {
this.status = ((MyTomcat) o).getStatus();
System.out.println("MySpring狀態與MyTomcat狀態(" + this.status + ")一致");
}
/**
* 模擬客戶端
*
* @param args
*/
public static void main(String[] args) {
// 創建觀察者對象
MySpring mySpring = new MySpring();
// 創建主題對象,並將觀察者對象添加入主題對象
MyTomcat myTomcat = new MyTomcat(mySpring);
myTomcat.setStatus("start");
myTomcat.setStatus("close");
}
}
/**
*MySpring狀態與MyTomcat狀態(start)一致
*MySpring狀態與MyTomcat狀態(close)一致
*/