今天給大家?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)題:
- 作為女孩,首先我要知道誰(shuí)喜歡我啊,不然通知錯(cuò)人了怎么辦?(實(shí)際情況是,盡管你知道有人喜歡你,但是這個(gè)人是誰(shuí)你知道嗎?)
- 又有人喜歡女孩了,也想照顧她。但是不想讓女孩知道,只想默默地付出。按照我們現(xiàn)在這種寫法,只有女孩知道誰(shuí)喜歡她才會(huì)通知到,不知道的就不通知了。
- 其他
使用觀察者模式有什么好處
看了我們上面的寫法,發(fā)現(xiàn)這種寫法是不合適的。我們有沒(méi)有解決辦法呢?
答案當(dāng)然是有啊。但是首先我們應(yīng)明確自己的需求。
- 我只要主動(dòng)關(guān)注女孩就行了,不用等通知,自己要主動(dòng),畢竟幸福靠自己爭(zhēng)取。
- 女孩魅力大,我們要允許其他人也喜歡(不限于A,B,C),畢竟每個(gè)人都有愛(ài)與被愛(ài)的權(quán)利。
所以,觀察者模式來(lái)救場(chǎng)。

(聲明下,我有空了就去學(xué)UML。這個(gè)畫的不夠標(biāo)準(zhǔn),希望能說(shuō)明問(wèn)題。)
那么對(duì)應(yīng)于我們這個(gè)例子,之間關(guān)系又是怎樣的呢?

那我們?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é)果:

好了,到此我們觀察者模式就簡(jiǎn)單地描述完了?;氐介_(kāi)篇前我們的兩個(gè)問(wèn)題,我們現(xiàn)在這種模式有沒(méi)有解決問(wèn)題呢?
- 作為女孩,首先我要知道誰(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í),我并不需要知道)。
- 又有人喜歡女孩了,也想照顧她。但是不想讓女孩知道,只想默默地付出。按照我們現(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)指正。