設計模式之觀察者模式
1.觀察者模式介紹
1.1> 設計模式可以說是一種代碼規範,也可以說是一種前人總結的技巧經驗,對於後來編程者,學習設計模式可以對編程思路有一些啓發,其中也包括經驗啓發。
1.2> 對象之間定義一對多的依賴關係,當一個對象發生變化時,依賴它的其他對象會收到通知並相應作出反應。發生改變的對象稱之爲觀察目標(被觀察者),收到通知並作出反應的對象稱之爲觀察者。一個觀察目標可以有多個觀察者,觀察者之間相互沒有任何關係,可以增加、刪除觀察者。
2.觀察者模式應用場景
2.1> 基礎的發佈、訂閱關係,比如:博主的粉絲訂閱,博主有更新或者回復的時候,給粉絲髮生通知,
2.2> 有一個微信公衆號服務,不定時發佈一些消息,關注公衆號就可以收到推送消息,取消關注就收不到推送消息。
2.3> 需要在系統中創建一個觸發鏈,A對象的行爲將影響B對象,B對象的行爲將影響C對象……,可以使用觀察者模式創建一種鏈式觸發機制。
3.觀察者模式代碼詳解?
3.1> 觀察者模式的結構
觀察者模式與發佈/訂閱模式的區別在於;通知調度的地方,觀察者模式中,通知調度的地方在於被觀察者中,而發佈/訂閱模式中有一個專門的調度中心。
3.2> 觀察者模式中主要的對象:2個接口;2個類
觀察目標(被觀察者)的抽象接口:觀察目標將觀察者保存在一個集合中,一個被觀察者可以有多個觀察者;觀察目標提供了 增加觀察者、刪除觀察者的接口。
觀察者的抽象接口:爲所有具體的觀察者提供一個接口,用於被觀察者發生改變時更新自己。
被觀察者的抽象類:存儲之被觀察者的對象,當其發生改變時,給所有關注的觀察者發送通知,一般通過具體的子類來實現。
觀察者抽象類:存儲相關狀態,通過具體子類實現觀察者的抽象接口,通過被觀察者的狀態更新自己。
3.3>
觀察目標抽象接口:
public interface BeObserver {
void addObserver(AbstractObserverDTO abstractObserverDTO);
void delObserver(AbstractObserverDTO abstractObserverDTO);
void notice(MessageDTO messageDTO);
}
定義了三個接口
1> 增加觀察者。
2> 刪除觀察者。
3> 通知觀察者,自身發送改變,通知觀察者。
被觀察者抽象類,具體子類繼承該類
public class AbstracBeObserverDTO implements BeObserver {
private String name;
private String age;
private List<AbstractObserverDTO> abstractObserverDTOS = new ArrayList<>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public void addObserver(AbstractObserverDTO abstractObserverDTO) {
abstractObserverDTOS.add(abstractObserverDTO);
}
@Override
public void delObserver(AbstractObserverDTO abstractObserverDTO) {
abstractObserverDTOS.remove(abstractObserverDTO);
}
@Override
public void notice(MessageDTO messageDTO) {
if (abstractObserverDTOS == null || abstractObserverDTOS.size() == 0) {
return;
}
for (AbstractObserverDTO abstractObserverDTO : abstractObserverDTOS) {
abstractObserverDTO.updateMsg(messageDTO);
}
}
}
實現了被觀察者的3個接口。具體的子類繼承該抽象類,重寫該類的接口。
public interface Observer {
/**
* 觀察者更新的方法
*
* @param messageDTO
*/
void updateMsg(MessageDTO messageDTO);
}
觀察者抽象接口:主要是當被觀察發生變更時,調用該方法通知觀察者
觀察者抽象類,實現了觀察者首相接口
public class AbstractObserverDTO implements Observer {
private String name;
private Date date;
private List<AbstractObserverDTO> abstractObserverDTOS = new ArrayList<>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
@Override
public void updateMsg(MessageDTO messageDTO) {
System.out.println(this.name + ":" + messageDTO.getName() + ":" + messageDTO.getMessage());
}
}
具體當觀察者子類繼承該類,並重寫該方法。
消息對象
public class MessageDTO {
private String message;
private Integer type;
private String name;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Integer getType() {
return type;
}
public void setType(Integer type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
別觀察者子類
public class BeObserverOneDTO extends AbstracBeObserverDTO {
private String note;
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
}
觀察者子類1
public class ObserverOneDTO extends AbstractObserverDTO {
private String note;
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
@Override
public void updateMsg(MessageDTO messageDTO) {
System.out.println(this.note + ":" + messageDTO.getName() + ":" + messageDTO.getMessage());
}
}
觀察者子類2
public class ObserverTwoDTO extends AbstractObserverDTO {
private String note;
private String sex;
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public void updateMsg(MessageDTO messageDTO) {
System.out.println(this.note + ":" + messageDTO.getName() + ":" + messageDTO.getMessage());
}
}
測試
public class TestMain {
public static void main(String[] args) {
ObserverOneDTO one = new ObserverOneDTO();
one.setNote("粉絲1");
ObserverTwoDTO two = new ObserverTwoDTO();
two.setNote("粉絲2");
two.setSex("女");
BeObserverOneDTO beObserverOneDTO = new BeObserverOneDTO();
beObserverOneDTO.setNote("zuiaicy");
beObserverOneDTO.setName("zuiaicy有博客更新");
beObserverOneDTO.addObserver(one);
beObserverOneDTO.addObserver(two);
MessageDTO messageDTO = new MessageDTO();
messageDTO.setMessage("設計模式之觀察者模式");
messageDTO.setName(beObserverOneDTO.getName());
messageDTO.setType(1);
beObserverOneDTO.notice(messageDTO);
}
}
測試結果:
粉絲1:zuiaicy有博客更新:設計模式之觀察者模式
粉絲2:zuiaicy有博客更新:設計模式之觀察者模式
優化:
1> 被觀察者的訂閱列表(觀察者列表)可以存數據庫。
2> 被觀察者發生變更時,可以通過異步方式調用觀察者的更新接口。
3> 許多地方還可以做得更加抽象。
4.觀察者模式的優缺點?
優點:
1> 面向接口編程的思想
2> 鬆耦合,改變了一方,不會影響到另一方。
3> 觀察者模式可以實現表示層和數據邏輯層的分離,定義了穩定的消息更新傳遞機制,並抽象了更新接口,使得可以有各種各樣不同的表示層充當具體觀察者角色。
4> 觀察者模式支持廣播通信,觀察目標會向所有已註冊的觀察者對象發送通知,簡化了一對多系統設計的難度。
5> 觀察者模式滿足“開閉原則”的要求,增加新的具體觀察者無須修改原有系統代碼,在具體觀察者與觀察目標之間不存在關聯關係的情況下,增加新的觀察目標也很方便。
不足:
1> 如果一個觀察目標對象有很多直接和間接觀察者,將所有的觀察者都通知到會花費很多時間。
2> 如果在觀察者和觀察目標之間存在循環依賴,觀察目標會觸發它們之間進行循環調用,可能導致系統崩潰。
3> 觀察者模式沒有相應的機制讓觀察者知道所觀察的目標對象是怎麼發生變化的,而僅僅只是知道觀察目標發生了變化。