java设计模式--观察者模式(Observer)
java設(shè)計模式--觀察者模式(Observer)
觀察者模式的定義:
定義對象間的一種一對多的依賴關(guān)系。當(dāng)一個對象的狀態(tài)發(fā)生改變時,所有依賴于它的對象
都得到通知并被自動更新。
認識觀察者模式:
1.目標和觀察者之間的關(guān)系:
按照模式的定義,目標和觀察者之間是典型的一對多的關(guān)系。
但是要注意,如果觀察者只有一個,也是可以的,這樣就變相的實現(xiàn)了目標和觀察者之間
一對一的關(guān)系。
?
2.觀察者模式中有四種對象:
Subject(目標對象),
Observer(定義觀察者接口),
ConcreteSubject(具體的目標實現(xiàn)對象),
ConcreteObserver(觀察者的具體實現(xiàn)對象)
一個目標可以有任意多個觀察者對象,一旦目標的狀態(tài)發(fā)生了改變,所有注冊的觀察者都會等到通知,
然后各個觀察者會對通知作出相應(yīng)的響應(yīng),執(zhí)行相應(yīng)的業(yè)務(wù)功能處理,并使自己的狀態(tài)和目標的狀態(tài)保存一致。
Subject:目標對象接口,提供如下功能:
a.一個目標可以被多個觀察者觀察
b.目標提供對觀察者注冊和退訂的維護
c.當(dāng)目標的狀態(tài)發(fā)生變化時,目標負責(zé)通知所有注冊的,有效的觀察者
Observer:觀察者的接口,提供目標通知時對應(yīng)的更新方法,這個方法進行相應(yīng)的業(yè)務(wù)處理,可以在這個方法
里面回調(diào)目標對象,以獲取目標對象的數(shù)據(jù)。
ConcreteSubject:具體的目標實現(xiàn)對象,用來維護目標狀態(tài),當(dāng)目標對象的狀態(tài)發(fā)生改變時,通知
所有注冊的、有效的觀察者,讓觀察者執(zhí)行相應(yīng)的處理。
ConcreteObserver:觀察者的具體實現(xiàn)對象,用來接收目標的通知,并進行相應(yīng)的后續(xù)處理,比如更新
自身的狀態(tài)以保持和目標的相應(yīng)狀態(tài)一致。
?
舉例:
?
/*** 功能:* 具體的目標對象,負責(zé)把有關(guān)狀態(tài)存入到相應(yīng)的觀察者對象* 并在自己狀態(tài)發(fā)生改變時,通知各個觀察者* (報紙對象)* @author Administrator**/ public class NewPaper extends Subject {//報紙的具體內(nèi)容private String content;/*** 功能:* 獲取報紙的具體內(nèi)容* @return*/public String getContent(){return content;}/*** 功能:* 設(shè)置報紙的具體內(nèi)容,相當(dāng)于出版報紙* @param content*/public void setContent(String content){this.content = content;//通知所有注冊的讀者this.notifyAllObservers();} }?
/*** 功能:* 觀察者接口,定義一個更新的接口給那些在目標發(fā)生改變的時候被通知的對象* (報紙的讀者)* @author Administrator**/ public interface Observer {/*** 功能:* 更新的接口* @param subject 傳入目標對象,方便獲取相應(yīng)的目標對象的狀態(tài)*/public void update(Subject subject); }?
/*** 功能:* 具體的觀察者對象,實現(xiàn)更新的方法,使自身的狀態(tài)和目標的狀態(tài)保存一致* (真正的讀者)* @author Administrator**/ public class Reader implements Observer {//讀者的姓名private String name;@Overridepublic void update(Subject subject){//這里采用拉的方式System.out.println(name + "收到報紙,內(nèi)容為: "+ ((NewPaper)subject).getContent());}public String getName(){return name;}public void setName(String name){this.name = name;} }?
public class Client {public static void main(String[] args){//創(chuàng)建一個報紙,作為被觀察者NewPaper subject = new NewPaper();//創(chuàng)建閱讀者,也就是觀察者Reader reader1 = new Reader();reader1.setName("羅納爾多");Reader reader2 = new Reader();reader2.setName("貝克漢姆");//注冊觀察者 subject.attach(reader1);subject.attach(reader2);subject.setContent("世界杯要開始了哦.....");} }?
?
對上面的模式進行講解:
一、目標和觀察者之間的關(guān)系
按照模式的定義,目標和觀察者之間是典型的一對多的關(guān)系。
但是,觀察者也可以只有一個,這樣就實現(xiàn)了目標和觀察者之間一對一的關(guān)系。
同樣,一個觀察者可以觀察多個目標。
?
觀察者模式中的: 推模型和拉模型
推模型:
目標對象主動向觀察者推送目標的詳細信息,不管觀察者是否需要,推送的信息通常是
目標對象的全部或部分數(shù)據(jù)
拉模型:
目標對象在通知觀察者的時候,只傳遞少量信息。如果觀察者需要更具體的信息,
由觀察者主動到目標對象中獲取,相當(dāng)于觀察者從目標對象中拉數(shù)據(jù)。
?
將上面的代碼通過推模型進行實現(xiàn):
import java.util.ArrayList; import java.util.List;/*** 功能:* 目標對象,作為被觀察者,使用推模型* @author Administrator**/ public class Subject { //用來保存注冊的觀察者對象(報紙訂閱者)private List<Observer> readers = new ArrayList<Observer>();/*** 功能:* 注冊觀察者對象(報紙的讀者需要向報社訂閱,先要注冊)* @param observer 觀察者對象*/public void attach(Observer reader){readers.add(reader);}/*** 功能:* 刪除觀察者對象(報紙的讀者可以取消訂閱)* @param observer*/public void detach(Observer reader){readers.remove(reader);}/*** 功能:* 通知所有的觀察者* (當(dāng)有報紙出版后,就要主動的送到讀者手中,相當(dāng)于通知讀者)*/protected void notifyAllObservers(String content){for(Observer reader : readers){reader.update(content);}} }?
public class NewsPaper extends Subject {private String content;public String getContent(){return content;}public void setContent(String content){this.content = content;//通知所有注冊的觀察者(讀者)this.notifyAllObservers(content);} }?
/*** 功能:* 觀察者(報紙的讀者)* @author Administrator**/ public interface Observer {/*** 功能:* 被通知的方法,直接把報紙的內(nèi)容推送過來* @param content*/public void update(String content); }?
public class Reader implements Observer {//讀者的姓名private String name;@Overridepublic void update(String content){//這里采用推的方式System.out.println(name + "收到報紙了,內(nèi)容是:" + content);}public String getName(){return name;}public void setName(String name){this.name = name;} }?
public class Client {public static void main(String[] args){//創(chuàng)建一個報紙,作為被觀察者NewsPaper subject = new NewsPaper();//創(chuàng)建閱讀者,也就是觀察者Reader reader1 = new Reader();reader1.setName("羅納爾多");Reader reader2 = new Reader();reader2.setName("貝克漢姆");//注冊觀察者 subject.attach(reader1);subject.attach(reader2);subject.setContent("世界杯要開始了哦.....");} }?
兩種模型的比較:(1)推模型是假定目標對象知道觀察者需要的數(shù)據(jù);而拉模型是目標對象不知道觀察者具體 需要什么數(shù)據(jù),沒有辦法的情況下,把自身傳給觀察者,讓觀察者自己去按需取值。 (2)推模型可能會使得觀察者對象難以復(fù)用,因為觀察者定義的update方法是按需而定義的, 可能無法兼顧沒有考慮到的使用情況。這就意味著出現(xiàn)新情況的時候,就可能需要提供新的update方法, 或者干脆重新實現(xiàn)觀察者。java中的觀察者在java.util包里面有一個類Observable,實現(xiàn)了大部分目標的功能。 java.util包里面有一個類Observer,其中定義了update的方法,就是觀察者的接口?
?
import java.util.Observable;public class NewsPaper extends Observable {//報紙的具體內(nèi)容private String content;/*** 功能:* 獲取報紙的具體內(nèi)容* @return*/public String getContent(){return content;}/*** 功能:* 設(shè)置報紙的具體內(nèi)容,相當(dāng)于出版報紙* @param content*/public void setContent(String content){this.content = content;//通知觀察者this.setChanged();this.notifyObservers(this.content);//采用推的方法 } }?
import java.util.Observable; import java.util.Observer;/*** 功能:* 觀察者(讀者)* @author Administrator**/ public class Reader implements Observer {private String name;public String getName(){return name;}public void setName(String name){this.name = name;}@Overridepublic void update(Observable arg0, Object obj){System.out.println(name + "收到報紙了,內(nèi)容為:"+obj);} }?
public class Client {public static void main(String[] args){//創(chuàng)建一個報紙,作為被觀察者NewsPaper subject = new NewsPaper();//創(chuàng)建閱讀者,也就是觀察者Reader reader1 = new Reader();reader1.setName("羅納爾多");Reader reader2 = new Reader();reader2.setName("貝克漢姆");//注冊閱讀者 subject.addObserver(reader1);subject.addObserver(reader2);//出版報紙subject.setContent("世界杯要開始了咯");} }?
觀察者模式的本質(zhì):觸發(fā)聯(lián)動
當(dāng)修改目標對象的狀態(tài)的時候,就會觸發(fā)相應(yīng)的通知,然后會循環(huán)的調(diào)用所有注冊的觀察者對象
的相應(yīng)方法,其實就相當(dāng)于聯(lián)動調(diào)用這些觀察者的方法。
這個聯(lián)動還是動態(tài)的,可以通過注冊和取消注冊來控制觀察者,因而可以可以在程序運行期間,
通過動態(tài)的控制觀察者,來變相地實現(xiàn)添加和刪除某些功能處理,這些功能就是觀察者在update的
時候執(zhí)行的功能。
轉(zhuǎn)載于:https://www.cnblogs.com/baiduligang/p/4247420.html
總結(jié)
以上是生活随笔為你收集整理的java设计模式--观察者模式(Observer)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MD3200扩展柜MD1200,玩起
- 下一篇: iOS UITableView