定義
觀察者(Observer)模式 又稱發佈-訂閱模式、模型-視圖模式,指多個對象間存在一對多的依賴關係,當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並被自動更新。
觀察者模式屬於對象行爲型模式。
要點
優點:
- 降低了目標與觀察者之間的耦合關係,兩者之間是抽象耦合關係。
- 目標與觀察者之間建立了一套觸發機制。
缺點:
- 目標與觀察者之間的依賴關係並沒有完全解除,而且有可能出現循環引用。
- 當觀察者對象很多時,通知的發佈會花費很多時間,影響程序的效率。
主要角色:
- 抽象主題(Subject):也叫抽象目標類,它提供了一個用於保存觀察者對象的聚集類和增加、刪除觀察者對象的方法,以及通知所有觀察者的抽象方法。
- 具體主題(Concrete Subject):也叫具體目標類,它實現抽象目標中的通知方法,當具體主題的內部狀態發生改變時,通知所有註冊過的觀察者對象。
- 抽象觀察者(Observer):它是一個抽象類或接口,它包含了一個更新自己的抽象方法,當接到具體主題的更改通知時被調用。
- 具體觀察者(Concrete Observer):實現抽象觀察者中定義的抽象方法,以便在得到目標的更改通知時更新自身的狀態。
場景
在嗶哩嗶哩視頻網站上,某UP主被粉絲關注之後,每當UP主更新作品時,訂閱該UP主的粉絲賬號消息中心會收到相關的提示通知。
實現
AbstractUPSubject
/**
* UP主,相當於抽象主題
*/
public abstract class AbstractUPSubject {
protected String upName;
protected List<FansObserver> fans = new ArrayList<>();
public AbstractUPSubject(String upName) {
this.upName = upName;
}
/**
* 粉絲訂閱
*/
public void addFan(FansObserver observer) {
if (observer != null) {
fans.add(observer);
}
}
/**
* 粉絲退訂
*/
public void removeFan(FansObserver observer) {
if (observer != null) {
fans.remove(observer);
}
}
/**
* 通知粉絲
*/
public abstract void notifyFans();
}
UPA
/**
* UP主A,相當於具體主題
*/
public class UPA extends AbstractUPSubject {
public UPA(String upName) {
super(upName);
}
@Override
public void notifyFans() {
fans.forEach(fan -> fan.response(upName));
}
}
UPB
/**
* UP主B,相當於具體主題
*/
public class UPB extends AbstractUPSubject {
public UPB(String upName) {
super(upName);
}
@Override
public void notifyFans() {
fans.forEach(fan -> fan.response(upName));
}
}
FansObserver
/**
* 粉絲,相當於抽象觀察者
*/
public interface FansObserver {
/**
* 粉絲對訂閱通知的響應
*/
void response(String upName);
}
FansA
/**
* 粉絲A,相當於具體觀察者
*/
public class FansA implements FansObserver {
private String fanName;
public FansA(String fanName) {
this.fanName = fanName;
}
@Override
public void response(String upName) {
System.out.println(String.format("嗨,【%s】,你關注的UP主【%s】發佈了新作品,快來查看吧!", fanName, upName));
}
}
FansB
/**
* 粉絲B,相當於具體觀察者
*/
public class FansB implements FansObserver {
private String fanName;
public FansB(String fanName) {
this.fanName = fanName;
}
@Override
public void response(String upName) {
System.out.println(String.format("嗨,【%s】,你關注的UP主【%s】發佈了新作品,快來查看吧!", fanName, upName));
}
}
Client
public class Client {
public static void main(String[] args) {
// UP主
AbstractUPSubject upA = new UPA("混世大魔王");
AbstractUPSubject upB = new UPB("櫻桃小丸子");
// 粉絲
FansObserver fanA = new FansA("小王");
FansObserver fanB = new FansB("小李");
// 訂閱UP主
upA.addFan(fanA);
upA.addFan(fanB);
upB.addFan(fanB);
// 通知
upA.notifyFans();
upB.notifyFans();
}
}
--------------------輸出----------------------
嗨,【小王】,你關注的UP主【混世大魔王】發佈了新作品,快來查看吧!
嗨,【小李】,你關注的UP主【混世大魔王】發佈了新作品,快來查看吧!
嗨,【小李】,你關注的UP主【櫻桃小丸子】發佈了新作品,快來查看吧!
源碼
總結
適用場景:
- 對象間存在一對多關係,一個對象的狀態發生改變會影響其他對象。
- 當一個抽象模型有兩個方面,其中一個方面依賴於另一方面時,可將這二者封裝在獨立的對象中以使它們可以各自獨立地改變和複用。
在 Java 中,通過 java.util.Observable 類和 java.util.Observer 接口定義了觀察者模式,只要實現它們的子類就可以編寫觀察者模式實例。