观察者模式详解

观察者模式

1.1观察者模式概述

观察者模式(Observer Pattern)又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式。定义了一种一对多的依赖关系,一个主题对象可被多个观察者对象同时监听,使得每当主题对象状态变化时,所有依赖它的对象都会得到通知并自动更新,属于行为型设计模式。
观察者的核心是将观察者与被观察者解耦,以类似消息/广播发送的机制联动两者,使被观察者的变动能通知到感兴趣的观察者们,从而做出相应的响应。

1.2观察者模式的应用场景

观察者模式一般会应用到App的闹钟设置,消息的广播通知,邮件通知等。

1.3观察者模式的通用写法

/**
 * 抽象主题者
 *
 * @author yml
 * @since 2022/4/13 11:24
 */
public interface ISubject {
    boolean attach(IObserver observer);

    boolean detach(IObserver observer);

    void notify(T event);
}
/**
 * 抽象观察者
 *
 * @author yml
 * @since 2022/4/13 11:21
 */
public interface IObserver {
    void update(T event);
}
/**
 * 具体主题者
 *
 * @author yml
 * @since 2022/4/13 14:46
 */
public class ConcreteSubject implements ISubject {

    private List> observers = new ArrayList>();
    @Override
    public boolean attach(IObserver observer) {
        return !this.observers.contains(observer) && this.observers.add(observer);
    }

    @Override
    public boolean detach(IObserver observer) {
        return this.observers.remove(observer);
    }

    @Override
    public void notify(T event) {
        for (IObserver observer:this.observers) {
            observer.update(event);
        }
    }
}
/**
 * 具体观察者
 *
 * @author yml
 * @since 2022/4/13 14:43
 */
public class ConcreteObserver implements IObserver {

    @Override
    public void update(T event) {
        System.out.println("receive event: " + event);
    }
}
/**
 * @Author:yml
 * @Data:2022/4/13
 */
public class ClientTest {
    public static void main(String[] args) {
        // 被观察者
        ISubject subject = new ConcreteSubject<>();
        // 观察者
        IObserver observer = new ConcreteObserver<>();
        // 将观察者注册
        subject.attach(observer);
        // 被观察者通知观察者
        subject.notify("hello");
    }
}

绘制出观察者uml图:

观察者模式详解
由上图可以看出,观察者模式主要包含4个角色:
  • 抽象主题(ISubject):指被观察的对象。该角色是一个抽象类或接口,定义了增加、删除、通知观察者对象的方法。
  • 具体主题(ConcreteSubject):具体被观察者,当其内部状态发生变化时,会通知已注册的观察者。
  • 抽象观察者(IObserver):定义了响应通知的更新方法。
  • 具体观察者(ConcreteObserver):当得到状态更新通知时,会自动做出响应。

2.1观察者模式的具体实现

2.1.1 JDK中的观察者模式

模拟一个场景,在线教育平台,当某个学生在线上提出问题并指出对应指导老师回答,指定老师则会收到相应邮件通知

import java.util.Observable;

/**
 * 被观察者
 *
 * @author yml
 * @since 2022/4/13 15:48
 */
public class GPer extends Observable {
    private String name = "GPer 平台";

    private static GPer gPer = null;

    private GPer(){}

    public static GPer newInstance(){
        if (null == gPer){
            gPer = new GPer();
        }
        return gPer;
    }

    public String getName() {
        return name;
    }

    public void publishQuestion(Question question){
        System.out.println(question.getUserName()+":"+question.getContent());
        setChanged();
        notifyObservers(question);
    }
}
/**
 * @Author:yml
 * @Data:2022/4/13
 */
public class Question {
    private String userName;

    private String content;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }
}
import java.util.Observable;
import java.util.Observer;

/**
 * @Author:yml
 * @Data:2022/4/13
 */
public class Teacher implements Observer {
    private String name;

    public Teacher(String name){
        this.name = name;
    }
    @Override
    public void update(Observable o, Object arg) {
        GPer gPer = (GPer) o;
        Question question = (Question) arg;
        System.out.println("===========================================");
        System.out.println(this.name + "老师,你好 \n" + "您收到一条来自" + gPer.getName() + "\n" + "提问者:" + question.getUserName() +
                "\n" + "问题描述:" + question.getContent());
    }
}
/**
 * @Author:yml
 * @Data:2022/4/13
 */
public class ClientTest {
    public static void main(String[] args) {
        GPer gPer = GPer.newInstance();
        Teacher tom = new Teacher("Tom");
        Teacher jerry = new Teacher("Jerry");

        gPer.addObserver(tom);
        gPer.addObserver(jerry);

        // 用户操作
        Question question = new Question();
        question.setUserName("amazing");
        question.setContent("如何学好JAVA");

        gPer.publishQuestion(question);
    }
}

观察者模式详解

2.1.2 基于Guava API实现观察者模式

需要引入maven依赖包


      com.google.guava
      guava
      20.0

import com.google.common.eventbus.EventBus;
import org.example.observereg.Question;

/**
 * @Author:yml
 * @Data:2022/4/13
 */
public class GuavaBus {
    public static final EventBus bus = new EventBus();

    public static void register(GuavaEvent event){
        if (event == null){
            return;
        }
        bus.register(event);
    }

    public static void question(Question question){
        bus.post(question);
    }
}
import com.google.common.eventbus.Subscribe;
import org.example.observereg.Question;

/**
 * @Author:yml
 * @Data:2022/4/13
 */
public class GuavaEvent {

    @Subscribe
    public void subscribe(Question question){
        System.out.println(question.getUserName()+":"+question.getContent());
    }
}
import org.example.observereg.Question;

/**
 * @Author:yml
 * @Data:2022/4/13
 */
public class GuavaEventTest {
    public static void main(String[] args) {
        GuavaEvent guavaEvent = new GuavaEvent();
        GuavaBus.register(guavaEvent);
        Question question = new Question();
        question.setUserName("amazing");
        question.setContent("如何学好JAVA");
        GuavaBus.question(question);

    }
}

观察者模式详解

3.1 观察这模式在Spring源码中的应用

Spring中的事件机制,Spring中的ContextLoaderListener实现ServletContextListener,ServletContextListener又继承JDK的EventListener,实现事件监听。

3.2 观察者模式的优缺点

  • 优点:
    1.观察者和被观察者都是松耦合(抽象耦合),符合依赖倒置原则。
    2.分离了表示层(观察者)和数据逻辑层(被观察者者),并且建立了一套触发机制,使得数据的变化可以响应到多个表示层。
    3.实现了一对多的通信机制,支持事件注册机制,支持兴趣分发机制,当被观察者触发时间是,只有订阅的观察者可以接受通知。
  • 缺点
    1.如果观察者过多,则事件通知会耗时较长。
    2.事件通知为线性,可能出现阻塞。
    3.观察者和被观察者可能存在循环依赖,可能造成循环调用,导致系统崩溃。

Original: https://www.cnblogs.com/amazing-yml/p/16139016.html
Author: amazing_yml
Title: 观察者模式详解

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/644109/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球