观察者模式

设计模式

本系列文章均是博主原创,意在记录学习上的知识,同时一起分享学习心得。

24种设计模式



前言

本章介绍观察者模式的定义、实现方式、应用场景。


提示:以下是本篇文章正文内容,下面案例可供参考

一、定义

观察者模式也被称为发布订阅模式,在对象之间定义一个一对多的依赖,当一个对象状态改变的时候,所以依赖的对象都会自动收到通知。
一般情况下,被依赖的对象叫作被观察者,依赖的对象叫作观察者。不过,在实际的项目开发中,这两种对象的称呼是比较灵活的,有各种不同的叫法,比如:Subject-Observer、Publisher-Subscriber、Producer-Consumer、EventEmitter-EventListener、Dispatcher-Listener。不管怎么称呼,只有应用场景符合定义,都可以被称作观察者模式。

二、实现方式

在不同的场景,观察者实现的方式都不一样,主要有同步阻塞的实现方式,也有异步非阻塞的实现方式;有进程内的实现方式,也有跨进程的实现方式。

1.常用的实现方式

观察者模式常用的实现步骤如下:

  1. 先定义一个观察者顶级接口,再根据实际需求,定义观察者实现类,可以有多个。
  2. 定义一个执行类,在执行类中会定义一个List,该list存储了所有的观察者类,在应用启动的时候就要初始化。
  3. 发布消息,在被观察者类中,若某个状态发生变更,可通过执行类来发布事件,执行类会循环调用观察者类进行事件推送。

代码如下(示例):

public interface RegObServer {

    void handleRegister(long userId);

}
public class RegNotificationObserver implements RegObServer {
    @Override
    public void handleRegister(long userId) {
        System.out.println("开始处理注册通知,通知用户:" + userId);
    }
}
public class RegPromotionObserver implements RegObServer{
    @Override
    public void handleRegister(long userId) {
        System.out.println("开始处理注册金发放,发放用户:" + userId);
    }
}
public class RegObserverion {

    private static final List<RegObServer> regObservers = new ArrayList<>();

    static {
        regObservers.add(new RegNotificationObserver());
        regObservers.add(new RegPromotionObserver());
    }

    public static void post(Long userId) {
        for (RegObServer regObServer : regObservers) {
            regObServer.handleRegister(userId);
        }
    }
}
@Test
public void test() {
    System.out.println("注册成功,开始处理注册后的操作...");
    RegObserverion.post(111111L);
}

在这里插入图片描述

2.通过EventBus实现观察者模式

观察者模式常用的实现方式是默认采用同步阻塞的方式,即在循环通知观察者类的时候,如果其中一个观察者发送异常,会影响后续的观察者类的执行,所以为了避免这种情况,我们可以将其改为异步通知的方式,而EventBus框架已经实现好了这么一种方式。

实现的逻辑步骤大致如下:

  1. 引入EventBus包依赖。
  2. 定义一组观察者类,要求观察者的方法加上@Subscribe注解,该注解的意思是,将该方法标记为一个观察者执行方法,并将该方法的参数和方法的类路径当作key-value存到EventBus的内部Map中;在实际执行过程中,EventBus会根据执行的参数来匹配这个方法的类路径,然后通过反射来执行该方法。

注意:通过参数来匹配执行方法时,会自动向上匹配其父类参数的执行方法。比如:有A、B两个参数,B参数为A参数的父类,那么在发布A参数类型作为事件参数时,会同时匹配到A参数、B参数对应的执行方法。

代码如下(示例):

		// 添加EventBus的依赖
		<dependency>
            <groupId>ch.cmbntr</groupId>
            <artifactId>eventbus</artifactId>
            <version>0.9.0</version>
        </dependency>
public class RegNotificationObserver {

    @Subscribe
    public void handleRegister(RegisterDto register) {
        System.out.println("注册完成,开始处理注册通知,通知用户:" + register);
    }

    @Subscribe
    public void handleRegisterSuccess(RegisterSuccessDto register) {
        System.out.println("注册成功,开始处理注册通知,通知用户:" + register);
    }

    @Subscribe
    public void handleRegisterFail(RegisterFailDto register) {
        System.out.println("注册失败,开始处理注册通知,通知用户:" + register);
    }
}
public class RegPromitionObserver {

    @Subscribe
    public void handleRegister(RegisterDto register) {
        System.out.println("注册完成,开始处理注册金发放,发放用户:" + register);
    }

    @Subscribe
    public void handleRegisterSuccess(RegisterSuccessDto registerSuccess) {
        System.out.println("注册成功,开始处理注册金发放,发放用户:" + registerSuccess);
    }

    @Subscribe
    public void handleRegisterFail(RegisterFailDto registerFail) {
        System.out.println("注册失败,开始处理注册金发放,发放用户:" + registerFail);
    }
}
    @Test
    public void eventBusTest() {
        EventBus eventBus = new EventBus();
        eventBus.register(new RegPromitionObserver());
        eventBus.register(new RegNotificationObserver());

        RegisterDto registerDto = new RegisterDto("0000", "注册完成", 111L);
        RegisterSuccessDto registerSuccessDto = new RegisterSuccessDto("0000", "注册完成", 111L, "success");
        RegisterFailDto registerFailDto = new RegisterFailDto("0000", "注册完成", 111L, "fail");

        Random random = new Random();
        int rd = random.nextInt(10);
        if (rd < 3) {
            eventBus.post(registerDto);
        } else if (rd >= 3 && rd < 7) {
            eventBus.post(registerSuccessDto);
        } else {
            eventBus.post(registerFailDto);
        }
    }

在这里插入图片描述


总结

同步阻塞式最经典的实现方式,主要是为了代码解耦;异步非阻塞除了能实现代码解耦之外,还能提高代码的执行效率;进程间的观察者模式解耦更加彻底,一般是基于消息队列来实现,用来实现不同进程间的被观察者和观察者之间的交互。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值