设计模式:观察者模式

原文链接:http://www.wangqi94.com/to/master/blog?uuid=75

前言


观察者模式是非常常用的设计模式之一。在软件系统中,当一个对象的行为依赖于另外一个对象的状态时,观察者模式就相当有用了。若不适用观察者模式提供的通用结构,而需要实现其类似的功能,则只能在另外一个线程中不停的监听对象所依赖的状态。在一个复杂的系统中,可能会因此开启很多线程来实现这一功能,这将是系统的性能产生额外的负担。观察者模式的意义也就在此,它可以在单线程中,是某一对象,即使得知自身所依赖的状态的变化。

什么是观察者模式


观察者模式的经典结构如下图所示:


观察者模式结构图.png

ISubject是被观察对象,它可以增加和删除观察者。IObserver是观察者对象,它依赖ISubject的状态变化。当ISubject状态发生变化时,会通过inform()方法通知观察者。

观察者模式的主要角色及作用:

`主题接口`:指被观察的对象。当其状态发生改变或者某事件发生时,它会将这个变化通知观察者,它维护了观察者所需要依赖的状态。

`具体主题`:具体主题实现了主题接口中的方法。如新增观者这、删除观者者和通知观察者。其内部维护了一个观察者列表。

`观察者接口`:观察者接口定义了观察者对象的基本方法。当依赖的状态发生变化时,主题接口就会调用观察者的update方法。

`具体观察者`:实现了观察者接口的update(),具体处理当被观察者状态改变时或者某一事件发生时的业务逻辑。

看下上述观察者结构对应的代码实现:
主题接口的实现:

/**
 * @Author: 王琦 <QQ.Eamil>1124602935@qq.com</QQ.Eamil>
 * @Date: 2019-4-30 0030 21:07
 * @Description: 主题接口 / 被观察者
 */
public interface ISubject {

    void attach(IObserver observer); // 添加观察者
    void detach(IObserver observer); // 删除观察者
    void inform();                   // 通知所有的观察者
}

观察者接口的实现:

/**
 * @Author: 王琦 <QQ.Eamil>1124602935@qq.com</QQ.Eamil>
 * @Date: 2019-4-30 0030 21:09
 * @Description: 观察者接口
 */
public interface IObserver {

    void update(Object event); // 更新事件
}

一个具体的主题实现,注意,它维护了观察者队列,提供了增加和删除观察者的方法,并通过inform()通知所有观察者。

/**
 * @Author: 王琦 <QQ.Eamil>1124602935@qq.com</QQ.Eamil>
 * @Date: 2019-4-30 0030 21:10
 * @Description: 一个具体的主题实现
 */
public class ConcreteSubject implements ISubject {

    Vector<IObserver> observers = new Vector<IObserver>();

    @Override
    public void attach(IObserver observer) {
        observers.addElement(observer);
    }

    @Override
    public void detach(IObserver observer) {
        observers.removeElement(observer);
    }

    @Override
    public void inform() {

        for (IObserver observer : observers){
            // 这里通知所有的观察者
            observer.update(null);
        }
    }
}

两个具体的观察者实现如下,当它监听的状态发生变化时,update()方法就会被主题回调,进而可以在观察者内部进行业务处理:

/**
 * @Author: 王琦 <QQ.Eamil>1124602935@qq.com</QQ.Eamil>
 * @Date: 2019-4-30 0030 21:13
 * @Description: 一个具体的观察者
 */
public class ConcreteObserver1 implements IObserver {

    @Override
    public void update(Object event) {
        System.out.println("observer1 receives information");
    }
}
/**
 * @Author: 王琦 <QQ.Eamil>1124602935@qq.com</QQ.Eamil>
 * @Date: 2019-4-30 0030 21:13
 * @Description: 一个具体的观察者
 */
public class ConcreteObserver2 implements IObserver {

    @Override
    public void update(Object event) {
        System.out.println("observer2 receives information");
    }
}

来,测试下,看看结果是否符合预期:

/**
 * @Author: 王琦 <QQ.Eamil>1124602935@qq.com</QQ.Eamil>
 * @Date: 2019-4-30 0030 21:15
 * @Description: 观察者模式测试
 */
public class SubjectObserverModelTest {

    public static void main(String[] args) {
        ISubject subject = new ConcreteSubject();
        IObserver observer1 = new ConcreteObserver1();
        IObserver observer2 = new ConcreteObserver2();

        // add 观察者
        subject.attach(observer1);
        subject.attach(observer2);
        // 通知
        subject.inform();

        System.out.println("----------------  分隔符  ---------------");

        // remove 观察者
        subject.detach(observer2);
        // 再次通知
        subject.inform();
    }
}

执行结果如下:


测试观察者模式执行结果.png

JDK提供了观察者模式


显然符合我们的预期。观察者模式是很简单,所以也比较常用,以至于JDK内部已经为开发人员准备了一套观察者模式的实现。它位于java.util包中,包括java.util.Observable类和java.util.Observer接口,他们的关系如下图所示:


JDK观察者模式关系图.png

在java.util.Observable类中,已经实现了主要的功能,如增加观察者、删除观察者和通知观察者,开发人员可以直接通过继承Observable使用这些功能。java.util.Observer接口是观察者接口,它的update()方法会在java.util.Observable的notifyObservers()方法中被回调,以获得最新的状态变化。通常在观察者模式中Observer接口总是应用程序的核心扩展对象,具体的业务逻辑总是会被封装在update()方法中。

总结


(1):观察者模式可以用于事件监听、通知发布等场合。可以确保观察者在不适用轮询监控的情况下,及时收到相关消息和事件。
(2):在JDK中已经实现了一套观察者模式,我们可以直接复用它。
RelaxHeart网 - Tec博客: 我的更多文章

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