觀察者模式(新手推薦)

今天給大家?guī)?lái)一個(gè)較為簡(jiǎn)單的模式,觀察者模式。如果覺(jué)得我寫得還不錯(cuò),記得關(guān)注下,我好有勇氣給大家以淺顯的語(yǔ)言介紹完這幾種設(shè)計(jì)模式。

為什么要使用觀察者模式?

舉個(gè)簡(jiǎn)單的例子,在一所工科學(xué)校里(我們都知道,工科院校女生都比較少),有一個(gè)很有教養(yǎng),漂亮,溫柔的女生大家都很喜歡,自然有很多人追。女生的一舉一動(dòng),大家都很關(guān)注。比如女生半夜發(fā)了個(gè)狀態(tài),說(shuō)“我餓了”。

。。。。。。

接下來(lái),不得了了,眾男們(假設(shè)現(xiàn)在有A,B,C三個(gè)男生同時(shí)喜歡上了改女生)著急了,都想用自己的方法讓女生填飽肚子(A:走,帶你吃KFC。B:別動(dòng),我給你買了送到你樓下。C:自己畫個(gè)餅,看看就行了)。當(dāng)然以C的這種方式,肯定沒(méi)戲,咳咳,扯遠(yuǎn)了。那么用偽代碼如何表示呢?

abstract class Boy{

//照顧自己身邊的人是每個(gè)男生義不容辭的責(zé)任
pulbic void careDarling();

}

// A 照顧人的方式
class BoyA extends Boy{

pulbic void careDarling(){
    
    System.out.println("走,帶你吃KFC");
}

}

//B 照顧人的方式

class BoyB extends Boy{

pulbic void careDarling(){
    
    System.out.println("別動(dòng),我給你買了送到你樓下");
}

}

//C 照顧人的方式

class BoyC extends Boy{

pulbic void careDarling(){
    
    System.out.println("自己畫個(gè)餅,看看就行了");
}

}

//下面這個(gè)是女孩類
class Girl{


public void hungrey(){
    
    //餓了,我們要通知A,B,C 是時(shí)候行動(dòng)了    
    BoyA.careDarling();
    BoyB.careDarling();
    BoyC.careDarling();

}

}

當(dāng)然,我們尊重每個(gè)人愛(ài)人的方式?,F(xiàn)在不是糾結(jié)這個(gè)的時(shí)候,我們看上面?zhèn)未a的表示有什么問(wèn)題嗎?

就在下看,有發(fā)現(xiàn)幾個(gè)問(wèn)題:

  1. 作為女孩,首先我要知道誰(shuí)喜歡我啊,不然通知錯(cuò)人了怎么辦?(實(shí)際情況是,盡管你知道有人喜歡你,但是這個(gè)人是誰(shuí)你知道嗎?)
  2. 又有人喜歡女孩了,也想照顧她。但是不想讓女孩知道,只想默默地付出。按照我們現(xiàn)在這種寫法,只有女孩知道誰(shuí)喜歡她才會(huì)通知到,不知道的就不通知了。
  3. 其他

使用觀察者模式有什么好處

看了我們上面的寫法,發(fā)現(xiàn)這種寫法是不合適的。我們有沒(méi)有解決辦法呢?
答案當(dāng)然是有啊。但是首先我們應(yīng)明確自己的需求。

  1. 我只要主動(dòng)關(guān)注女孩就行了,不用等通知,自己要主動(dòng),畢竟幸福靠自己爭(zhēng)取。
  2. 女孩魅力大,我們要允許其他人也喜歡(不限于A,B,C),畢竟每個(gè)人都有愛(ài)與被愛(ài)的權(quán)利。

所以,觀察者模式來(lái)救場(chǎng)。

觀察者模式結(jié)構(gòu)

(聲明下,我有空了就去學(xué)UML。這個(gè)畫的不夠標(biāo)準(zhǔn),希望能說(shuō)明問(wèn)題。)

那么對(duì)應(yīng)于我們這個(gè)例子,之間關(guān)系又是怎樣的呢?

新的結(jié)構(gòu)

那我們?yōu)楹尾挥么a實(shí)現(xiàn)下呢?

Observer

public interface Observer {

public void update();
}

Boy

public abstract class Boy {

public abstract void careDarling();
}

BoyA

public class BoyA extends Boy implements Observer {

private Subject subject;
public BoyA(Subject subject){
    subject.addObserver(this);
}

@Override
public void update() {
    careDarling();
}

@Override
public void careDarling() {
    System.out.println("走,帶你吃KFC");
}
}

BoyB

public class BoyB extends Boy implements Observer {

private Subject subject;
public BoyB(Subject subject){
    subject.addObserver(this);
}
@Override
public void update() {
    careDarling();
}

@Override
public void careDarling() {
    System.out.println("別動(dòng),我給你買了送到你樓下");
}
}

BoyC

public class BoyC extends Boy implements Observer {

private Subject subject;
public BoyC(Subject subject){
    subject.addObserver(this);
}

@Override
public void update() {
    careDarling();
}

@Override
public void careDarling() {
    System.out.println("自己畫個(gè)餅,看看就行了");
}

}

Subject

public interface Subject {

public void addObserver(Observer boy);
public void removeObserver(Observer boy);
public void notifyObservers();    
}

Girl

public class Girl implements Subject {

private List<Observer> boys;

public Girl(){
    boys = new ArrayList<Observer>();
}

@Override
public void addObserver(Observer boy) {
    
    boys.add(boy);

}

@Override
public void removeObserver(Observer boy) {
    boys.remove(boy);
}

@Override
public void notifyObservers() {
    
    for(int i=0;i<boys.size();i++){
        boys.get(i).update();
    }
}

public void hungrey(){
    notifyObservers();
}

}

測(cè)試類ObserverTest

public class ObserverTest {

public static void main(String[] args) {
    
    //小天使來(lái)到世界上
    Girl girl = new Girl();
    //護(hù)花使者A
    BoyA boyA = new BoyA(girl);
    //護(hù)花使者B
    BoyB boyB = new BoyB(girl);
    //護(hù)花使者C
    BoyC boyC = new BoyC(girl);
    //出大事了,小可愛(ài)餓了
    girl.hungrey();
}
}

結(jié)果:

result

好了,到此我們觀察者模式就簡(jiǎn)單地描述完了?;氐介_(kāi)篇前我們的兩個(gè)問(wèn)題,我們現(xiàn)在這種模式有沒(méi)有解決問(wèn)題呢?

  1. 作為女孩,首先我要知道誰(shuí)喜歡我啊,不然通知錯(cuò)人了怎么辦?(實(shí)際情況是,盡管你知道有人喜歡你,但是這個(gè)人是誰(shuí)你知道嗎?)

我們現(xiàn)在在Girl(Subject實(shí)現(xiàn)類)中維護(hù)一個(gè)數(shù)組或者隊(duì)列,用來(lái)保存觀察者。并不需要知道觀察者是誰(shuí)。我們?cè)趧?chuàng)建Girl的時(shí)候?qū)㈥?duì)列初始化(換句話說(shuō),我知道肯定有人喜歡我,但是具體是誰(shuí),我并不需要知道)。

  1. 又有人喜歡女孩了,也想照顧她。但是不想讓女孩知道,只想默默地付出。按照我們現(xiàn)在這種寫法,只有女孩知道誰(shuí)喜歡她才會(huì)通知到,不知道的就不通知了。

現(xiàn)在即便是有BoyC,BoyD出現(xiàn),在創(chuàng)建的時(shí)候就自己偷偷關(guān)注了女孩,當(dāng)女孩餓了的時(shí)候,并不需要改變?cè)械拇a就可實(shí)現(xiàn)通知所有的。(多好,我們的這種實(shí)現(xiàn)方式。畢竟暗戀也是美好的)。

然而在實(shí)際中,主題Subject在通知觀察者Observer的時(shí)候會(huì)攜帶一些數(shù)據(jù),這就不得不提一下觀察者模式的兩種模式:推(push)模式和拉(pull)模式

推模型:顧名思義,就是我不管你Observer想要什么,我給你什么你接收什么就是了。這種模式的使用場(chǎng)景就是需求較簡(jiǎn)單,且Subject和Observer類協(xié)商好返回?cái)?shù)據(jù)的類型。弊端當(dāng)然也很明顯就是眾Observer口難調(diào),我不知道你想要什么,大家返回都一樣??梢韵胂蟪扇涡缘呐?,我給你什么你要也得接受,不要也得接受。

全寫的話量有點(diǎn)大,所以只貼部分代碼:

public interface Subject {
public void addObserver(Observer boy);
public void removeObserver(Observer boy);
public void notifyObservers(int state);
}

可以看出,這個(gè)地方我們將state作為參數(shù)傳出去,然后在Observer中被動(dòng)接收。

public interface Observer {

public void update(int state);
//舉個(gè)例子,這時(shí)候我們就可以在BoyA,BoyB...等中針對(duì)具體狀態(tài)作出相應(yīng)動(dòng)作。比如餓了怎么樣,困了怎么樣......
}

拉模型:就是觀察者(Observer)自己站起來(lái)了,想要什么就給什么。一般我們把主題類該類對(duì)象作為參數(shù)傳遞出去,然后觀察者可以利用反射等方式拿到自己想要的,推模型的問(wèn)題解決了,大家(眾多觀察者)可以各取所需??梢赃@么理解,付出這么多,女孩追到手了,把自己都交給你了。

public interface Subject {
public void addObserver(Observer boy);
public void removeObserver(Observer boy);
public void notifyObservers(Subject subject);
}

Girl

...

@Override
public void notifyObservers(Subject subject) {
    
    for(int i=0;i<boys.size();i++){
        boys.get(i).update(subject);
    }
}

public void hungrey(){
    
    notifyObservers(this);//將自己傳出去
}
...

Observer

public interface Observer {

public void update(Subject subject);//人都得到了,想知道什么還難嗎?

}

好了,觀察者模式到此介紹完畢,大家有什么問(wèn)題可以與我討論。當(dāng)然文中錯(cuò)誤在所難免,懇請(qǐng)批評(píng)指正。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容