观察者模式实战:解密最热门的设计模式之一

本文详细介绍了观察者模式在Java和Spring框架中的应用,包括观察者接口、具体观察者、基础发布者和具体发布者的实现,展示了如何通过事件类和事件监听器实现对象状态变化时的通知机制。
摘要由CSDN通过智能技术生成

前言

随着系统的复杂度变高,我们就会采取各种各样的优化手段来进行解耦,降低系统的复杂度,其中设计模式是古人经验的一种设计总结,场景一:发送消息的时候,需要采取不同的消息发送渠道,一次发送一个或者多个渠道,这种不确定的变化,我们就可以采用观察者模式来进行解耦,当一个对象状态发生改变时,其他依赖对象的状态也随之变更,这是观察者模式的核心。

注:本篇文章纯干货,采用Java的设计模式以及Spring设计模式实现,另外设计编码了交互页面,能够更直观体验观察者模式之美

一、什么是观察者模式

观察者模式是一种行为设计模式,类似于【发布订阅】,定义对象间的一种【一对多】的依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。

二、Java实现观察者模式

2.1 观察者接口

/**
 * 监听(观察者)接口
 * @author: DT辰白 Created by 2024/5/3 8:09
 */
public interface EventListener {

    void update(String message);

}

2.2 具体观察者

/**
 * 具体观察者
 * @author: DT辰白 Created by 2024/4/28 20:12
 */
@Slf4j
@Service
public class EmailListener implements EventListener {

    @Override
    public void update(String message) {
        log.info("邮箱:QQ邮箱发送消息,消息内容【{}】",message);
    }
}
/**
 * 具体观察者
 * @author: DT辰白 Created by 2024/4/28 20:14
 */
@Slf4j
@Service
public class SmsListener implements EventListener {

    @Override
    public void update(String message) {
        log.info("短信:短信发送消息,消息内容【{}】", message);
    }
}

2.3 基础发布者

这里我们使用了@Autowired注入,其实默认的实现类【EmailListener 、SmsListener】已经注入了,你也可以将List 做成一个普通的List集合,然后在使用的时候,将订阅对象添加到该List集合。

/**
 * @author: DT辰白 Created by 2024/4/28 20:17
 */
@Component
public class EventManager {

    @Autowired
    private List<EventListener> listeners;

    /**
     * 订阅
     * @param eventListeners
     */
    public void subscribe(EventListener... eventListeners) {
        for (EventListener eventListener : eventListeners) {
        	// 防止重复注入
            if (!listeners.contains(eventListener)) {
                this.listeners.add(eventListener);
            }
        }
    }

    /**
     * 取消订阅
     * @param eventListeners
     */
    public void unsubscribe(EventListener... eventListeners) {
        for (EventListener eventListener : eventListeners) {
            listeners.remove(eventListener);
        }
    }

    /**
     * 通知
     * @param message
     */
    public void notify(String message) {
        for (EventListener eventListener : listeners) {
            eventListener.update(message);
        }
    }
}

2.4 具体发布者

这里我们直接继承父类,可以通过子类调用父类的方法,我们也可以将此处做成一个抽象接口对外提供,具体方法有很多,根据自己的业务需求即可。

/**
 * 具体发布者
 * @author: DT辰白 Created by 2024/4/28 20:25
 */
@Service
public class MessagePublisher extends EventManager {

    public void publishMessage(String message) {
        notify(message);
    }

}

2.5 消息发送

@PostMapping(value = "/publishMessage")
@ApiOperation(value = "观察者模式【java】->发送消息")
public ResultUtil publishMessage(String message) {
    // 订阅(默认订阅全部)
    // messagePublisher.subscribe(emailListener,smsListener);
    // 取消订阅
    // messagePublisher.unsubscribe(smsListener);
    // 发布
    messagePublisher.publishMessage(message);
    return ResultUtil.success();
}
2024-05-03 08:25:17.049  INFO 12896 --- [nio-9091-exec-4] c.d.m.d.pattern.observer.EmailListener   : 邮箱:QQ邮箱发送消息,消息内容【我是一条鱼】
2024-05-03 08:25:17.049  INFO 12896 --- [nio-9091-exec-4] c.d.m.d.pattern.observer.SmsListener     : 短信:短信发送消息,消息内容【我是一条鱼】

三、Spring实现观察者模式

3.1 定义事件类

/**
 * 定义事件类
 * @author: DT辰白 Created by 2024/4/28 21:33
 */
public class NotificationEvent extends ApplicationEvent {

    private String message;

    public NotificationEvent(Object source, String message) {
        super(source);
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}

3.2 具体观察者

/**
 * @author: DT辰白 Created by 2024/4/28 21:34
 */
@Slf4j
@Component
public class EmailNotificationListener {
    @EventListener
    public void onApplicationEvent(NotificationEvent event) {
        // 发送邮件通知
        log.info("邮箱:QQ邮箱发送消息,消息内容【{}】",event.getMessage());
    }
}
/**
 * @author: DT辰白 Created by 2024/4/28 21:34
 */
@Slf4j
@Component
public class SMSNotificationListener {
    @EventListener
    public void onApplicationEvent(NotificationEvent event) {
        // 发送短信通知
        log.info("短信:短信发送消息,消息内容【{}】", event.getMessage());
    }
}

3.3 具体发布者

/**
 * 发布者接口
 * @author: DT辰白 Created by 2024/4/28 21:35
 */
public interface NotificationService {

    void notifyUsers(String message);
}
/**
 * 事件发布者
 * @author: DT辰白 Created by 2024/4/28 21:35
 */
@Service
public class NotificationPublisher implements NotificationService {

    @Autowired
    private ApplicationEventPublisher publisher;

    @Override
    public void notifyUsers(String message) {
        publisher.publishEvent(new NotificationEvent(this, message));
    }
}

3.4 消息发送

@PostMapping(value = "/publishMsg")
@ApiOperation(value = "观察者模式【spring】->发送消息")
public ResultUtil publishMsg(String message) {
    notificationService.notifyUsers(message);
    return ResultUtil.success();
}
2024-05-03 10:39:14.302  INFO 12680 --- [nio-9091-exec-3] c.d.m.d.p.o.s.EmailNotificationListener  : 邮箱:QQ邮箱发送消息,消息内容【我是一条鱼】
2024-05-03 10:39:14.302  INFO 12680 --- [nio-9091-exec-3] c.d.m.d.p.o.s.SMSNotificationListener    : 短信:短信发送消息,消息内容【我是一条鱼】

以上方式为同步发送,如果不需要保证数据一致性,只要其中一个渠道消息发送成功即可,我们可以采用异步的方式发送,这样就不会影响其它正常的渠道发送,当然也是我们项目中常用的方式,发送失败的渠道,采用补偿机制或者人工介入重新发送即可。
在这里插入图片描述
最后,为了更直观的体验观察者模式,我们设计了一个交互页面:

在这里插入图片描述

总结

观察者模式是一种行为设计模式,定义了一种一对多的依赖关系,当一个对象状态发生变化时,所有依赖它的对象都会得到通知并自动更新。Spring中的事件驱动模型就是观察者模式的典型应用。

  • 28
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DT辰白

你的鼓励是我创作的源泉

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值