设计模式之观察者模式

原创
2019/09/10 21:39
阅读数 139

简介

观察者模式(Observer Pattern)隶属于设计模式中的行为型模式。通过发布事件来将状态变化与处理逻辑解耦开来,可以拥有更好的可扩展性和可维护性。

定义

观察者模式,又叫发布-订阅模式,通过定义对象间一种一对多的依赖关系,使得当每一个对象改变状态,则所有依赖于他的对象都会得到通知。

观察者模式是典型的生产者消费者问题模式,被观察的对象状态改变后产生事件,对此事件感兴趣的观察者可以做出某些行为。

角色

观察者模式的角色可分为两类,总共四种角色,分别是:

  • 抽象被观察者,在日常实践中可以不存在
  • 具体被观察者
  • 抽象观察者,在实践中一般是listener
  • 具体观察者,接受事件,作出反应

在Java 中,jdk 自带了观察者模式需要的接口,分别是 被观察者Observable, 抽象观察接口 Observer,遗憾的是Java 中的被观察者Observable 是一个类而不是接口,在需要继承的场景中就无法使用它提供的功能了。

模式说明

消息队列可以说是观察者模式的高级别应用了,直接提升到了中间件的高度,不过我们还是在具体代码里来说明这个模式。

以前在写单一职责原则时举过登录成功之后使用观察者模式来通知各方,以实现登录主逻辑和登录后的记录、短信通知等操作解耦开来,在写开闭原则的时候也举了一个订单付款后的例子,也是观察者模式。有兴趣的可以去看一下。

今天我们使用图书馆来举例,假设图书馆提供借书服务,但是一本书可能有多个人来借却只能借给一个人,其他人就只能等前一个借书的人还了之后再来借,但是让人一遍遍来询问就太耗费时间了,我们通过观察者模式将书被还回来的事件通知给感兴趣的借书人,他们就可以在收到通知后来图书馆借书了。

这里我们直接使用 Java 提供的功能和接口

import java.util.Observable;
import java.util.Observer;

/**
 * 借阅的学生
 * @author dylan
 */
public class Student implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println(arg + " 还回来了");
    }
}



/**
 * 图书馆
 */
public class Library extends Observable {
    private Set<String> books = new HashSet<>(Arrays.asList("基业长青", "大象", "构建之法", "Unix 环境编程"));

    /**
     * 借出书籍
     *
     * @param book 被借的书
     */
    public void lend(String book) {
        books.remove(book);
    }

    /**
     * 书籍还回来
     *
     * @param book 被还的书
     */
    public void returnBack(String book) {
        books.add(book);

        // 通知所有等待的借书人
        notifyObservers(book);
    }

    public static void main(String[] args) {
        Student lily = new Student();
        Student adam = new Student();

        Library library = new Library();
        library.addObserver(lily);
        library.addObserver(adam);

        library.setChanged();

        library.lend("大象");
        //两个学生都收到了书送还的通知
        library.returnBack("大象");
    }
}

注意在使用 Java 提供的 Observable 类时,如果需要将事件通知出去,需要调用 setChange 方法

使用场景

  • 一个对象A对另一个对象B的状态改变感兴趣,但是B 对于 A 的存在并不感兴趣
  • 一个对象的状态改变要通知给多个对象
  • 观察者对象可以动态增减的
  • 两个对象并没有紧耦合的需求,并且对象的依赖是单方向的
  • 不同进程甚至系统之间的通信也可以使用观察者模式

优点

  • 职责解耦,对象的状态变化无需由自己负责,而只需要发布一个事件就可以了
  • 可以支持级联事件触发
  • 观察者模式可以支持广播通信
  • 观察者模式符合开闭原则

缺点

  • 观察者模式中观察者也可以成为被观察者,由于是解耦的,所以对象之间的依赖比较模糊
  • 如果观察者比较多,事件处理会比较耗时
  • 如果一个被观察者A有10个观察者,而每个观察者也有10个观察者,在A 状态改变发布事件后,会产生110 个消息需要处理,如果不小心的话,会产生事件风暴
  • 如果观察者与被观察者之间产生了循环,系统会崩溃
  • 观察者接收到的事件只是一个结果,对于事件是如何触发的并不清楚

最佳实践

  • 观察者模式一般只有 1 级,最多不超过 3级,因为观察者模式与正常的对象调用不一样,在代码中是看不到具体的调用链的,级数太多会导致处理流程不清晰
  • 观察者模式在 GUI 编程中使用的最多,在 Android 的开发中会有各种的 onChangeListner
  • 简单的消息处理可以使用代码模式来实现观察者,复杂一点或者对消息的可靠性、持久化有要求的场景可以使用消息中间件
  • 在框架的设计中,由于框架需要将自身状态变化通知到使用方,会有很多的观察者模式应用。
展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部