原文地址:http://te-amo.site/user/article/info/ARTICLE20180407063327367
文章中部分定義和解釋性文字,都是引用百度百科,主要的代碼及場景應用爲本人原創
一個目標物件管理所有相依於它的觀察者物件,並且在它本身的狀態改變時主動發出通知
場景:我在設計我個人網站時,有一個留言功能。其中有一個需求是:當管理員在後臺回覆留言後,要做三件事(1)更改數據庫,將處理完的留言標記爲已處理(2)將答覆內容通過郵件發送給留言人(3)給管理員一個提示告訴他,郵件已經發出。
其實面對這個場景,完全可以使用順序的方式來完成這一系列操作,先更新數據庫,再發送郵件,最後給管理員消息提示。但是這種設計不容易拓展與維護,如果以後需要增加新的操作,是需要修改整個邏輯結構。鑑於這個三個操作沒有嚴格的關聯要求,所以可以使用觀察者模式。
設計
構成
- 抽象觀察者角色:爲所有的具體觀察者定義一個接口,在得到主題通知時更新自己。(Observer)
- 具體被觀察者角色:也就是一個具體的主題,在集體主題的內部狀態改變時,所有登記過的觀察者發出通知。(LeaveMessageSubject)
- 具體觀察者角色:實現抽象觀察者角色所需要的更新接口,一邊使本身的狀態與製圖的狀態相協調。(ChangeDB,NotifyMessage,ReplyEmail)
實現
代碼地址:https://github.com/telundusiji/designpattern
Observer 抽象觀察者
public interface Observer {
void update(Message message);
}
ChangeDB 具體觀察者,更新數據庫
@Slf4j
public class ChangeDB implements Observer {
public void update(Message message) {
log.info("留言:{},{},{},在數據庫中更新!",message.id,message.name,message.content);
}
}
NotifyMessage 具體觀察者 給管理員進行消息提示
@Slf4j
public class NotifyMessage implements Observer{
public void update(Message message) {
log.info("留言:{},{},{},已通過郵件回覆",message.id,message.name,message.content);
}
}
ReplyEmail 具體觀察者 發送郵件
@Slf4j
public class ReplyEmail implements Observer {
public void update(Message message) {
log.info("留言:{},{},{},發送郵件...",message.id,message.name,message.content);
}
}
LeaveMessageSubject 具體被觀察者 message更新時通知所有觀察者
public class LeaveMessageSubject {
List<Observer> observers;
private Message message;
public LeaveMessageSubject() {
observers = new ArrayList<Observer>();
}
public void addObserver(Observer observer){
observers.add(observer);
}
public boolean removeObserver(Observer observer){
return observers.remove(observer);
}
public void notifyObserver(){
for(Observer o : observers){
o.update(message);
}
}
public void setMessage(Message message) {
this.message = message;
notifyObserver();
}
}
Message 留言實體
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Message {
int id;
String name;
String email;
String content;
}
經典應用
在servlet中Listener就是使用觀察者模式
- EventListener 抽象的觀察者
- ServletContextAttributeListener,ServletRequestAttributeListener…都是具體觀察者
- HttpServletRequest…可以認爲是具體被觀察者
例如:當HttpServletRequest 調用setAttribute方法時,就會去調用notifyAttributeAssigned方法,此方法會創建對應的事件對象,然後通知所有觀察改事件的觀察則進行更新
具體細節可以去看源碼