设计模式之观察者模式
前言:
觀察者模式(Observer Pattern)定義了一種一對(duì)多的依賴關(guān)系,讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽(tīng)某一個(gè)主題對(duì)象。這個(gè)主題對(duì)象在狀態(tài)發(fā)生變化時(shí),會(huì)通知所有觀察者對(duì)象,使他們能夠自己更新自己。
一.觀察者模式簡(jiǎn)介:
觀察者模式(Observer Pattern)應(yīng)用在當(dāng)一個(gè)對(duì)象的改變,需要同時(shí)改變其他對(duì)象的時(shí)候,實(shí)現(xiàn)了兩個(gè)相互協(xié)作的對(duì)象不會(huì)為了保持一致性而耦合在一起,這兩個(gè)對(duì)象都依賴于各自的抽象。
二.觀察者模式的實(shí)例講解:
案例:學(xué)生們觀察老師講課時(shí)的動(dòng)態(tài),決定是否繼續(xù)睡覺(jué)或者繼續(xù)抄作業(yè)。
1.產(chǎn)品設(shè)計(jì)UML類圖:
(圖片加載慢,多刷新幾下,耐心等待……)
注:指揮者類Client和Observer、Subject的實(shí)現(xiàn)類是依賴關(guān)系。
2.通知者抽象類(主題類):
設(shè)計(jì)分析:Subject類把所有對(duì)觀察者對(duì)象的引用保存在一個(gè)聚集里,每個(gè)主題都可以有任何數(shù)量的觀察者,抽象主題增加一個(gè)接口,可以增加和刪除觀察者對(duì)象。抽象主題類可以被多個(gè)具體主題類繼承。
package com.pattern.observer.subject;import com.pattern.observer.observer.Observer;/*** 通知者抽象類*/ public abstract class Subject {// 通知者狀態(tài)protected String subjectState;// 獲取通知者狀態(tài)public String getSubjectState() {return subjectState;}// 設(shè)置通知者狀態(tài)public void setSubjectState(String subjectState) {this.subjectState = subjectState;}// 添加觀察者public abstract void addObserver(Observer observer);// 刪除觀察者public abstract void removeObserver(Observer observer);// 通知觀察者public abstract void notifyObserver(); }3.老師通知者類(具體主題類):
設(shè)計(jì)分析: 將有關(guān)狀態(tài)存入觀察者對(duì)象,在主題內(nèi)部狀態(tài)改變的時(shí)候,給所有觀察者發(fā)信息。
在本例中,老師的行為受到所有學(xué)生的關(guān)注,一旦反生改變,將會(huì)通知(notifyObserver())學(xué)生改變(update())行為。比如:正在打瞌睡的同學(xué),看到老師過(guò)來(lái),會(huì)立馬打起精神。正在語(yǔ)文課上,抄數(shù)學(xué)作業(yè)的人,會(huì)立馬收起作業(yè),假裝認(rèn)真的讀語(yǔ)文書(shū)。
package com.pattern.observer.subject;import java.util.ArrayList; import java.util.List;import com.pattern.observer.observer.Observer;public class ChineseTeacher extends Subject {// 所有學(xué)生集合(所有觀察者集合)private List<Observer> studentList = new ArrayList<Observer>();@Overridepublic void addObserver(Observer observer) {studentList.add(observer);}@Overridepublic void removeObserver(Observer observer) {studentList.remove(observer);}// 通知觀察者@Overridepublic void notifyObserver() {for (Observer o : studentList) {// 提醒觀察者,做出反應(yīng)o.update();}}// 設(shè)置通知者狀態(tài)@Overridepublic void setSubjectState(String subjectState) {// 接收狀態(tài),并設(shè)置super.setSubjectState(subjectState);}// 獲取通知者狀態(tài)@Overridepublic String getSubjectState() {// 獲取狀態(tài)return super.getSubjectState();}}4.觀察者抽象類
設(shè)計(jì)分析: 抽象觀察者,為所有的具體觀察者定義一個(gè)接口,在得到主題的通知時(shí),通知自己。抽象觀察者類可以被多個(gè)具體觀察者繼承。
package com.pattern.observer.observer;import com.pattern.observer.subject.Subject;public abstract class Observer {protected String name;protected Subject subject;public Observer(String name, Subject subject) {super();this.name = name;this.subject = subject;}public abstract void update(); }5.學(xué)生觀察者類(具體觀察者類)
①:打瞌睡的學(xué)生觀察者類
package com.pattern.observer.observer;import com.pattern.observer.subject.Subject;/*** 瞌睡的學(xué)生(具體觀察者類)*/ public class SleepStudent extends Observer {// 構(gòu)造方法public SleepStudent(String name, Subject subject) {super(name, subject);}// 觀察者做出反應(yīng)@Overridepublic void update() {System.out.println(subject.getSubjectState() + "!" + name + ",下雨了,別睡了");}}②抄作業(yè)的學(xué)生觀察者類:
package com.pattern.observer.observer;import com.pattern.observer.subject.Subject;/*** 抄作業(yè)的學(xué)生(具體的觀察者類)* */ public class CopyHomeworkStudent extends Observer {// 構(gòu)造方法public CopyHomeworkStudent(String name, Subject subject) {super(name, subject);}// 觀察者做出反應(yīng)@Overridepublic void update() {System.out.println(subject.getSubjectState() + "!" + name + ",高數(shù)能考及格了,就別抄數(shù)學(xué)作業(yè)了");}}5.客戶端中使用:
設(shè)計(jì)分析: 客戶端需要依賴指揮著類和具體的建造者類,通過(guò)指揮者中的方法,控制建造者繪制具體的人物畫(huà)像,使得建造者類中的代碼和客戶端的表示層代碼分離,降低耦合度。
注:本客戶端用到Java的Swing繪圖,若不了解如何用Java繪圖,請(qǐng)點(diǎn)擊參考本人另一篇博文介紹《 Java用JFrame、JPanel、Graphics繪圖案例講解》。
package com.pattern.observer.client;import com.pattern.observer.observer.CopyHomeworkStudent; import com.pattern.observer.observer.SleepStudent; import com.pattern.observer.subject.ChineseTeacher;/*** 客戶端類*/ public class Client {public static void main(String[] args) {// 實(shí)例化通知者ChineseTeacher chTeacher = new ChineseTeacher();// 實(shí)例化觀察者SleepStudent sleepStudent = new SleepStudent("王臣", chTeacher);CopyHomeworkStudent copyStudent = new CopyHomeworkStudent("田壯", chTeacher);// 通知者添加被通知對(duì)象chTeacher.addObserver(sleepStudent);chTeacher.addObserver(copyStudent);// 通知者改變狀態(tài)chTeacher.setSubjectState("我要找?guī)讉€(gè)同學(xué)爬黑板");// 發(fā)出通知chTeacher.notifyObserver();} }6.運(yùn)行結(jié)果展示:
我要找?guī)讉€(gè)同學(xué)爬黑板!王臣,下雨了,別睡了 我要找?guī)讉€(gè)同學(xué)爬黑板!田壯,高數(shù)能考及格了,就別抄數(shù)學(xué)作業(yè)了7.源碼下載
本文示例代碼下載地址:點(diǎn)擊下載
三.總結(jié):
1.觀察者模式的優(yōu)點(diǎn):
- 觀察者對(duì)象和主題對(duì)象之間是接觸耦合的,二者都依賴于各自的抽象,體現(xiàn)出依賴倒轉(zhuǎn)原則的應(yīng)用。
- 建立了一套觸發(fā)機(jī)制,可以當(dāng)一個(gè)對(duì)象改變時(shí),同時(shí)改變其他對(duì)象(類似Oracle的觸發(fā)器)。
2.觀察者式的缺點(diǎn):
- 觀察者只能知道主題對(duì)象發(fā)生變化的狀態(tài),卻不能知道主題對(duì)象是怎么發(fā)生變化的。
- 耗時(shí)增加,當(dāng)有很多觀察者時(shí),通知所有的觀察者會(huì)花費(fèi)很多時(shí)間。
總結(jié)
以上是生活随笔為你收集整理的设计模式之观察者模式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: CSS 实战: Switch 按钮开关(
- 下一篇: Educational Codeforc