观察者模式

回复“000”获取程序员必备电子书

大家好,我是老田,今天我给大家分享设计模式中的观察者模式。用贴切的生活故事,以及真实项目场景来讲设计模式,最后用一句话来总结这个设计模式。

故事

昨晚上,睡觉之前,我看了一段《兵法》,在第二十四卷中,看到这么一句:敌不动,我不动

看完这个后,我忽然想起一个设计模式:观察者模式

老田是个喜欢学习春秋战国时期的历史和人文故事,有通道之人,可以私聊!

为什么会想到哦观察者模式呢?请听老田慢慢道来。

本文目录:

关于设计模式系列,前面我们已经分享过9种设计模式:

三国演义:责任链模式

韩信拜将:委派模式

3年工作必备  装饰器模式

工作五年了,居然还不懂  门面模式

点外卖,让我想起了 策略模式

初级必备:单例模式的7个问题

快速掌握 模板方法 模式

五分钟 掌握 原型模式

泡图书馆,我想到了 享元模式

言归正传,我们先来看看观察者模式的定义。

定义

观察者模式(Observer Pattern)又叫作发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependent)模式。

定义一种一对多的依赖关系,一个主题对象可被多个观察者对象同时监听,使得每当主题对象状态变化时,所有依赖它的对象都会得到通知并被自动更新,属于行为型设计模式

英文定义:

Defines a one-to-many dependency relationship betweenobjects so that each time an object's state changes,its dependentobjects are notified and automatically updated.

观察者模式的核心是将观察者与被观察者解耦,以类似消息/广播发送的机制联动两者,使被观察者的变动能通知到感兴趣的观察者们,从而做出相应的响应。

通用代码实现

观察者进行抽象:

//抽象观察者
public interface Observer {
    //反应
    void response();
}

两个观察者:

//观察者1
public class ConcreteObserver1 implements Observer {
    @Override
    public void response() {
        System.out.println("具体观察者1作出反应!");
    }
}
//观察者2
public class ConcreteObserver2 implements Observer {
    @Override
    public void response() {
        System.out.println("具体观察者2作出反应!");
    }
}

被观察者(目标)进行抽象:

import java.util.ArrayList;
import java.util.List;

//抽象目标
public abstract class Subject {
    protected List<Observer> observers = new ArrayList<Observer>();
    //增加观察者方法
    public void add(Observer observer) {
        observers.add(observer);
    }
    //删除观察者方法
    public void remove(Observer observer) {
        observers.remove(observer);
    }
    public abstract void notifyObserver(); //通知观察者方法
}

具体被观察者:

public class ConcreteSubject extends Subject {
    @Override
    public void notifyObserver() {
        System.out.println("具体目标发生改变...");
        System.out.println("--------------");
        for (Object obs : observers) {
            ((Observer) obs).response();
        }
    }
}

测试类:

public class ObserveTest {
    public static void main(String[] args) {
        Subject subject = new ConcreteSubject();
        Observer obs1 = new ConcreteObserver1();
        Observer obs2 = new ConcreteObserver2();
        subject.add(obs1);
        subject.add(obs2);
        subject.notifyObserver();
    }
}

运行结果:

具体目标发生改变...
--------------
具体观察者1作出反应!
具体观察者2作出反应!

通用代码UMML图

角色

UML图中,我们可以总结出,在观察者模式中有以下四个角色:

  • 抽象主题(Subject):指被观察的对象。该角色是一个抽象类或接口,定义了增加、删除、通知观察者对象的方法。
  • 具体主题(ConcreteSubject):具体被观察者,当其内部状态变化时,会通知已注册的观察者。
  • 抽象观察者(Observer):定义了响应通知的更新方法。
  • 具体观察者(ConcreteObserver1ConcreteObserver1):当得到状态更新的通知时,会自动做出响应。

下面我们来看看一个写生活中的观察者模式的场景。

观察者模式的应用场景

观察者模式在现实生活中的应用也非常广泛,比如:各种APP上的各种消息提示、学校铃声、公众号文章提示、各大网站消息提示等。用图解释:

.......

在软件系统中,当系统一方行为依赖另一方行为的变动时,可使用观察者模式松耦合联动双方,使得一方的变动可以通知到感兴趣的另一方对象,从而让另一方对象对此做出响应。

观察者模式主要适用于以下应用场景。

  • 当一个抽象模型包含两方面内容,其中一方面依赖另一方面。
  • 其他一个或多个对象的变化依赖另一个对象的变化。
  • 实现类似广播机制的功能,不需要知道具体收听者,只需分发广播,系统中感兴趣的对象会自动接收该广播。
  • 多层级嵌套使用,形成一种链式触发机制,使得事件具备跨域(跨越两种观察者类型)通知。

下面我们就用Java代码来实现观察者模式。

案例实现

JDK中的观察者模式

其实在JDK的util包内为我们提供了一套观察者模式的实现,在使用的时候我们只需要继承Observable和Observer类即可,其实观察者模式十分简单,推荐阅读JDK的实现代码真心没有几行。此外在JDK的实现中还增加了一个布尔类型的changed域,通过设置这个变量来确定是否通知观察者。

下面来实现一个微信给所用用户发送"端午安康":

//消息
public class Message {
    private String content;

public Message(String content) {
        this.content = content;
    }

public String getContent() {
        return content;
    }

public void setContent(String content) {
        this.content = content;
    }
}

平台给用户发消息

import java.util.Observable;
//APP平台
public class App extends Observable {

private String name;

public App(String name) {
        this.name = name;
    }

public void publishMsg(Message message) {
        System.out.println(this.name + " 平台 给 用户们发送消息");
        //setChanged是Observable中的方法
        setChanged();
         //notifyObservers也是Observable中的方法
        notifyObservers(message);
    }

public String getName() {
        return name;
    }

public void setName(String name) {
        this.name = name;
    }
}

下面是用户收到消息:

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

public class User implements Observer {

private String userName;

public User(String userName) {
        this.userName = userName;
    }
    //实现了Observer的update方法
    @Override
    public void 的update方法(Observable o, Object arg) {
        App app=(App)o;
        Message message=(Message)arg;
        System.out.println(this.userName+" 收到 "+ app.getName()+" 平台 的消息,内容:"+message.getContent());
    }
}

测试类

public class JDKObserverTest {
    public static void main(String[] args) {
        App app = new App("微信");
        Message message = new Message("端午安康!");

User tian = new User("田哥");
        app.addObserver(tian);

User zhang = new User("勇哥");
        app.addObserver(zhang);

User li = new User("苗哥");
        app.addObserver(li);

User xi = new User("西哥");
        app.addObserver(xi);

User bing = new User("兵哥");
        app.addObserver(bing);
        
        app.publishMsg(message);
    }
}

运行结果:

微信 平台 给 用户们发送消息
兵哥 收到 微信 平台 的消息,内容:端午安康!
西哥 收到 微信 平台 的消息,内容:端午安康!
苗哥 收到 微信 平台 的消息,内容:端午安康!
勇哥 收到 微信 平台 的消息,内容:端午安康!
田哥 收到 微信 平台 的消息,内容:端午安康!

微信平台给大家发了"端午安康!",对应观察者就能收到"端午安康!"的消息。

在Observable中我们可以对观察者进行添加、删除以及消息通知等操作。

基于Guava API 实现观察者模式

在guava中,也有一套关于观察者模式的,具体实现如下:

添加maven依赖

<dependency>
   <groupId>com.google.guava</groupId>
   <artifactId>guava</artifactId>
   <version>20.0</version>
 </dependency>

创建Event实现类

public class GuavaEvent {
    //guava包下的注解
    @Subscribe
    public void subscribe(String str) {
        //业务逻辑
        System.out.println("执行 subscribe 方法,入参为 " + str);

}
}

测试类:

public class GuavaEventTest {
    public static void main(String[] args) {
        EventBus eventBus = new EventBus();
        GuavaEvent guavaEven = new GuavaEvent();
        eventBus.register(guavaEven);
        eventBus.post("hello world!");
    }
}

运行结果:

执行 subscribe 方法,入参为 hello world!

小结

客户端只要创建一个EventBus,然后把我们实现的Event注册进去,再把对应的消息放进去,对应我们实现的Event就可以收到客户端发送的消息。

EventBus内部也提供来一系列的方法来供我们方便使用:

  • register 方法作为添加观察者
  • unregister方法删除观察者
  • post 方法发送通知消息等

使用起来非常方便。添加@Subscribe注解就可以创建一个订阅者了,具体的使用方式可以看看官网。

Spring中的观察者模式

在Spring中有一个ApplicationListener,也是采用观察者模式来处理的,ApplicationEventMulticaster作为主题,里面有添加,删除,通知等。

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

/**
  * Handle an application event.
  * @param event the event to respond to
  */
 void onApplicationEvent(E event);
}

另外,Spring中的ContextLoaderListener实现了ServletContextListener接口,ServletContextListener接口又继承了EventListener,在JDK中,EventListener有非常广泛的应用。

其实,我们在很多框架中,只要看到XxxListener样式的类,基本上都是观察者模式的实现。

安卓开发中的观察者模式

在Android中我们有一个常用的回调:对于View点击事件的监听。现在我们就来分析一下对于View的监听。

通常在我们使用的时候是这样的:

xxxView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // do something
            }
});

这样我们就注册好了一个回调函数,这也是观察者模式的实现。

观察模式扩展

优缺点

优点

  • 观察者和被观察者是松耦合(抽象耦合)的,符合依赖倒置原则。
  • 分离了表示层(观察者)和数据逻辑层(被观察者),并且建立了一套触发机制,使得数据的变化可以响应到多个表示层上。
  • 实现了一对多的通信机制,支持事件注册机制,支持兴趣分发机制,当被观察者触发事件时,只有感兴趣的观察者可以接收到通知。

缺点

  • 如果观察者数量过多,则事件通知会耗时较长。
  • 事件通知呈线性关系,如果其中一个观察者处理事件卡壳,则会影响后续的观察者接收该事件。
  • 如果观察者和被观察者之间存在循环依赖,则可能造成两者之间的循环调用,导致系统崩溃。

总结

从本文内容,我们很容易看出,观察者模式其实是围绕了解耦的思想来写的,观察者模式作为行为型设计模式,主要也是为了不同的业务行为的代码解耦。最后一句话来总结:

敌不动,我不动

好了,今天的分享就到这里,希望大家能明白什么是观察者模式,也希望大家以后在面试的时候就不要再说你不会设计模式了。

如果有技术探讨、需要学习资源等,请加我微信。

(0)

相关推荐

  • 图解Java设计模式之观察者模式

    天气预报项目需求 1)气象站可以将每天测量到的湿度.温度.气压等等以公告的形式发布出去(比如发布到自己的网站或第三方). 2)需要设计开放型API,便于其他第三方也能接入气象站获取数据. 3)提供温度 ...

  • 软件设计模式修炼 -- 观察者模式

    观察者模式是一种经常使用的设计模式,在软件系统中对象并不是孤立存在的,一个对象行为的改变可能会导致其他与之存在依赖关系的对象行为发生改变,观察者模式用于描述对象之间的依赖关系. 模式动机 很多情况下, ...

  • 使用C#的计时器加观察者模式完成报警推送需求

    前言 这两天面试了一个物联网公司高级研发,面试题是下面这样子 公司领导,部门主管,小组组长,组成员4级,假如有个 疫情预警,先通知组人员(对个人,主要有一个处理就算处理了) 如果3分钟没处理,就往组长 ...

  • 【2/25】在Game上应用观察者模式(Observer Pattern)

    这是<小游戏从0到1设计模式重构>系列内容第2篇,所有源码及资料在"程序员LIYI"公号回复"小游戏从0到1"获取. 作者使用过的最简洁的观察者模式 ...

  • PHP设计模式之观察者模式

    PHP设计模式之观察者模式 观察者,貌似在很多科幻作品中都会有这个角色的出现.比如我很喜欢的一部美剧<危机边缘>,在这个剧集中,观察者不停的穿越时空记录着各种各样的人或事.但是,设计模式中 ...

  • [PHP小课堂]PHP设计模式之观察者模式

    [PHP小课堂]PHP设计模式之观察者模式 关注公众号:[硬核项目经理]获取最新文章 添加微信/QQ好友:[DarkMatterZyCoder/149844827]免费得PHP.项目管理学习资料

  • PHP设计模式—观察者模式

    定义: 观察者模式(Observer):定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象.这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己. 结构: Eve ...

  • 行为型模式之观察者模式

    在现实世界中,许多对象并不是独立存在的,其中一个对象的行为发生改变可能会导致一个或者多个其他对象的行为也发生改变.例如,某种商品的物价上涨时会导致部分商家高兴,而消费者伤心. 在软件世界也是这样,例如 ...

  • 设计模式(20) 观察者模式

    观察者模式是一种平时接触较多的模式.它主要用于一对多的通知发布机制,当一个对象发生改变时自动通知其他对象,其他对象便做出相应的反应,同时保证了被观察对象与观察对象之间没有直接的依赖. GOF对观察者模 ...

  • 无废话设计模式(15)行为型模式--观察者模式

    0-前言 观察者模式定义:定义了一种一对多的依赖关系让多个观察者对象同事监听某一主题对象. 这个主题对象在状态发生改变时,会通知所有观察者对象,使他们能够自动更新自己: 1-实现 1-1.简单UML图 ...