觀察者模式
觀察者模式屬於行爲型模式,又叫發佈訂閱模式
定義:
定義對象間一種一對多的依賴關係,使得每當一個對象改變狀態,則所有依賴於它的對象都會得到通知並被自動更新
模式類圖
角色:
- 被觀察者:Subject定義一個被觀察者必須實現職責,包括動態增加,刪除,通知觀察者
- 觀察者:Observer接受到觀察者修改消息,執行自身邏輯
- 具體觀察者:ConctreteSubject繼承Subject,擁有自己的業務邏輯,具有被觀察者基本功能,對某些事件進行通知
- 具體的觀察者:ConcreteObserver具體觀察者,在接受到被觀察者變更消息後,進行各自業務處理
優點
-
觀察者和被觀察者之間是抽象耦合,容易拓展
-
通過觸發機制可以創建成一種鏈式觸發機制,形成多級觸發
缺點
-
執行效率
當通知觀察者是順序執行時,需要考慮整個觀察者列表的數量,對整個通知事件執行效率的影響,可以考慮使用異步通知,同時儘量避免多級觸發事件 -
循環依賴
當觀察者和被觀察之間形成循環依賴,會導致循環調用,比如A改變通知B,B改變通知C,C改變通知A,注意避免循環依賴的發生
被觀察者接口
Subjectable 定義被觀察者基本功能
public interface Subjectable {
/**
* 增加觀察者
*/
void addObserver(Observerable observer);
/**
* 移除觀察者
*/
void removeObserver(Observerable observer);
/**
* 通知觀察者
*/
void notifyObserver(Object object);
}
被觀察者抽象類
AbstractSubject被觀察者類的公共父類,實現了被觀察者基本功能的實現,使用Vector爲觀察者列表
public abstract class AbstractSubject implements Subjectable{
/**
* 觀察者列表
*/
private Vector<Observerable> observers = new Vector();
@Override
public void addObserver(Observerable observer){
observers.add(observer);
}
@Override
public void removeObserver(Observerable observer){
observers.add(observer);
}
@Override
public void notifyObserver(Object object){
observers.forEach(observer->{
observer.update(object);
});
}
}
被觀察者類
UserInfo實現AbstractSubject
@Data
public class UserInfo extends AbstractSubject{
/**
* 暱稱
*/
private String nickName;
/**
* 密碼
*/
private String password;
/**
* 修改密碼
* @param password
*/
public void updatePassword(String password){
this.password = password;
this.notifyObserver(password);
}
public UserInfo(String nickName, String password) {
this.nickName = nickName;
this.password = password;
}
}
觀察者接口
public interface Observerable {
/**
* 被觀察者變化觸發事件
*/
void update(Object object);
}
具體觀察者
SmsObserver 接收到被觀察者密碼變更,發送短信提醒
public class SmsObserver implements Observerable {
@Override
public void update(Object object) {
if(null == object){
return;
}
System.out.println("短信觀察者");
System.out.println("短信發送提醒:密碼更改爲:"+object.toString());
}
}
EmailObserver 接收到被觀察者密碼變更,發送郵件提醒
public class EmailObserver implements Observerable{
@Override
public void update(Object object) {
if(null == object){
return;
}
System.out.println("郵件觀察者");
System.out.println("郵件發送提醒:密碼更改爲:"+object.toString());
}
}
驗證
public static void main(String[] args) {
UserInfo userInfo = new UserInfo("麻辣香鍋","malaxiangguo");
SmsObserver smsObserver = new SmsObserver();
EmailObserver emailObserver = new EmailObserver();
userInfo.addObserver(smsObserver);
userInfo.addObserver(emailObserver);
userInfo.updatePassword("mlxg");
}
輸出
短信觀察者
短信發送提醒:密碼更改爲:mlxg
郵件觀察者
郵件發送提醒:密碼更改爲:mlxg
SmsObserver和EmailObserver觀察到UserInfo用戶麻辣香鍋更改密碼爲mlxg
參考:設計模式之禪:https://www.kancloud.cn/sstd521/design/193589