设计模式之观察者模式

观察者模式是使用最为频繁的设计模式之一。在很多地方都有用到。比如各种编程语言的GUI事件处理实现,各种框架的实现,比如说EventBus、Rxjava以及MVC等等。

一、初次相识

先举个小栗子来了解一下观察者是干啥的~~

当我们在打团队游戏时,当你受到攻击需要队友帮忙时该怎么办?

这时候就需要给你所有的队友发送一条你正在被攻击的消息。所有的队友会根据你发送的消息作出相应的动作。比如有团队意识来帮你,或者不帮你继续玩自己的。

这里面的队员就是该设计模式名字中的观察者。那么受到攻击的自己的是什么呢。被观察者?不,准确的我们称之为目标或者主题。

所以整个流程大概就是:当目标(主题)的状态发送改变时就会通知观察者,观察者根据自己的情况做出相应的动作。

二、进步熟悉

通过上面我们大概对观察者的作用有了浅层的认识,这对接下来的学习很有帮助。

1.首先来看一下观察者模式(Observe Pattern)的正经定义:定义对象之间的一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。

它还有几个别名:发布-订阅模式、模型-视图模式、源-监听器模式以及从属者模式。比如我们看这个发布-订阅模式就很好理解,当订阅者订阅了某系列杂志,当杂志有了新的状态,比如更新了,那么此时就会给所有的订阅者发送一条消息,那么所有的订阅者就会收到此消息做出购买或不购买的选择。

2.那么它如何实现这么神奇的功能的呢?

先来看一下它的结构图


从图中我们可以看到之前说的目标和观察者。只不过这里的目标和观察者都被抽象化了。我们来逐一认识:

(1)Subject(目标或主题)

它是指被观察的对象。我们在主题中定义一个观察者集合。一个观察者对象可以接收任意多个观察者。同时提供了一系列的方法管理这些观察者。

比如attach添加观察者到集合中,detach从集合中剔除观察者。notify通知集合中的所有观察者。

(2)ConcreteSubject(具体目标)

它拥有自己的状态,当它的状态的改变时就会通知各个观察者。

同时还实现了在目标类中定义的抽象逻辑方法(如果有的话)

(3)Observer(抽象观察者)

它是一个接口,观察者将对观察目标状态的改变做出相应的反应

该接口定义了更新数据的方法update

(4)ConcreteObserver(具体观察者)

具体观察者中会维护一个指向具体目标对象的引用,它存储了具体观察者的状态,这些状态和具体目标的状态要保持一致。

它实现了抽象观察者对象的updata方法。

通常在实现时,可以调用具体目标的attach和detach方法将自己加入到集合中或者从集合中剔除。

3.接下来通过一个代码实例来加深对上面的结构图的理解

目标抽象类 Subject.java

public abstract class Subject {     

protected ArrayList observers=new ArrayList<>();     

//把观察者对象添加到观察者集合中     

public void attach(Observer observer) {           

observers.add(observer);     

}     

//把观察者对象剔除到观察者集合中     

public void detach(Observer observer) {           

observers.remove(observer);     

}                         

//声明抽象方法     

public abstract void notifyObserver();}

具体目标类 ConcreteSubject.java 继承抽象类并实现通知观察者的方法

public class ConcreteSubject extends Subject{     

//实现通知的方法     

@Override     

public void notifyObserver() {           

System.out.println("目标对象状态已变化......发送通知给观察者中");           

for(Object object:observers){                   

((Observer)object).update();           

}                 

}}

观察者接口 Observer 定义一个更新的方法

//观察者接口

public interface Observer {     

public void update();

}

具体的观察者 ConcreteSubject.java

public class ConcreteObserver implements Observer {     

private String observerName;     

public ConcreteObserver(String observerName) {           

this.observerName=observerName;     

}     

@Override     

public void update() {           

System.out.println(observerName+"我要更新一下我的状态了......");      }

}

这里再添加一个具体的观察者,测试是否能够同时收到消息并更新状态ConcreteOberverOther.java

public class ConcreteOberverOther implements Observer{     

private String observerName;             

public ConcreteOberverOther(String observerName) {           

this.observerName=observerName;     

}             

@Override     

public void update() {           

System.out.println(observerName+"我要更新一下我的状态了......");     

}

}

最后准备一个类测试一下:

public class NotifyMain {     

public static void main(String[] args) {           

Subject subject=new ConcreteSubject();           

Observer observer=new ConcreteObserver("观察者一号");         

  Observer observer2=new ConcreteOberverOther("观察者二号");           

subject.attach(observer);           

subject.attach(observer2);           

subject.notifyObserver();     

}

}

将两个观察者通过attach添加到观察者集合中,然后由目标来发送一条更新的消息。观察者接收到消息后做出反应。运行结果如下:


三、总结告别

对于上面的分析,我么对观察者设计模式就有了一个相对比较清晰的认识。但要对它能够熟练的使用,还需要一定的时间练习。

那么最后我们来总结一下它的优缺点,让我们能更好的使用它。

1.主要优点

(1)观察者模式可以实现表示层和数据逻辑层的分离,定义了稳定的消息传递机制,并抽象了更新接口,使得可以有各种各样的表示层充当具体的观察者角色。

(2)观察者模式在观察目标和观察者之间建立一个抽象的耦合。观察者对象只需要维持一个抽象观察者的集合,无需了解其具体观察者。

(3)观察者模式支持广播通信,观察目标会向所有已注册的观察者发送通知,降低了一对多系统的设计难度。

(4)观察者模式满足开闭原则的要求,增加新的具体观察者无须修改原有的系统代码。

2.主要缺点

(1)如果一个观察目标对象有很多的直接观察者和间接观察者,那么所有的观察者接收到消息会耗费大量的时间。

(2)如果观察者和被观察者之间存在循环依赖,那么观察目标会触发它们之间进行循环调用,可能导致系统崩溃。

(3)观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道目标观察对象发生了变化。

设计模式是软件开发人员的内功,要想成为绝世高手,深厚的内功功底必不可少。让我们一起来修炼这内功,让它成为我们成长路上的垫脚石吧。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 198,154评论 5 464
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,252评论 2 375
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 145,107评论 0 327
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,985评论 1 268
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,905评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,256评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,978评论 3 388
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,611评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,891评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,910评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,736评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,516评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,995评论 3 301
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,132评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,447评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,034评论 2 343
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,242评论 2 339

推荐阅读更多精彩内容