- 定義對象間的一種一個對多的依賴關系,當一個對象的狀態(tài)發(fā)送改變時,所以依賴于它的對象都得到通知并被自動更新。
一、觀察者模式
- 抽象主題(Subject):它把所有觀察者對象的引用保存到一個集合中,每個主題都可以有任何數(shù)量的觀察者。抽象主題提供一個接口,可以注冊和移除觀察者。
- 具體主題(ConcreteSubject):將有關狀態(tài)存入具體觀察者對象;在具體主題內部狀態(tài)改變時,給所有登記過的觀察者發(fā)出通知。
- 抽象觀察者(Observer):為所有的具體觀察者定義一個接口,在得到主題通知時更新自己。
- 具體觀察者(ConcreteObserver):實現(xiàn)抽象觀察者提供的更新接口,以便本身的狀態(tài)能夠及時更新。
(1)代碼實現(xiàn)
- 抽象觀察者:定義一個接到通知的更新方法
public interface Observer {
void update(Observable o, Object arg);//更新方法
}
- 具體觀察者
public class ConcreteObserverA implements Observer {
private String name;
public ConcreteObserverA(String name) {
this.name = name;
}
@Override
public void update(Observable o, Object arg) {
System.out.println("觀察者" + name + "---->" + arg.toString());
}
}
public class ConcreteObserverB implements Observer {
private String name;
public ConcreteObserverB(String name) {
this.name = name;
}
@Override
public void update(Observable o, Object arg) {
System.out.println("觀察者" + name + "---->" + arg.toString());
}
}
- 抽象主題:抽象被觀察者
public class Observable {
private boolean changed = false;
private Vector<Observer> 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 (!hasChanged())
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;
}
//觀察者數(shù)量
public synchronized int countObservers() {
return obs.size();
}
}
- 具體主題:具體被觀察者
public class ConcreteSubject extends Observable {
private static ConcreteSubject concreteSubject;
private List<Observer> list = new ArrayList<>();
public static ConcreteSubject getInstance() {
if (null == concreteSubject) {
synchronized (ConcreteSubject .class) {
if (null == concreteSubject) {
concreteSubject = new ConcreteSubject();
}
}
}
return concreteSubject;
}
@Override
public synchronized void addObserver(Observer o) {
list.add(o);
}
@Override
public synchronized void deleteObserver(Observer o) {
if (list.contains(o)) {
list.remove(o);
}
}
@Override
public synchronized void deleteObservers() {
list.clear();
}
@Override
public void notifyObservers(Object arg) {
for (Observer observer : list) {
observer.update(null, arg);
}
}
}
- 調用實現(xiàn)
ConcreteObserverA concreteObserverA = new ConcreteObserverA("小張");
ConcreteObserverB concreteObserverB = new ConcreteObserverB("小李");
ConcreteSubject.getInstance().addObserver(concreteSubjectA);
ConcreteSubject.getInstance().addObserver(concreteSubjectB);
ConcreteSubject.getInstance().notifyObservers("觀察者請刷新信息");
- 解除觀察者與主題之間的耦合。讓耦合的雙方都依賴于抽象,而不是依賴具體。從而使得各自的變化都不會影響另一邊的變化。
- 易于擴展,對同一主題新增觀察者時無需修改原有代碼。
- 依賴關系并未完全解除,抽象主題仍然依賴抽象觀察者。
- 使用觀察者模式時需要考慮一下開發(fā)效率和運行效率的問題,程序中包括一個被觀察者、多個觀察者,開發(fā)、調試等內容會比較復雜,而且在Java中消息的通知一般是順序執(zhí)行,那么一個觀察者卡頓,會影響整體的執(zhí)行效率,在這種情況下,一般會采用異步實現(xiàn)。
- 可能會引起多余的數(shù)據(jù)通知。