前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >设计模式之观察者模式:实现松耦合通信

设计模式之观察者模式:实现松耦合通信

作者头像
程序视点
发布2023-09-13 12:33:14
2080
发布2023-09-13 12:33:14
举报
文章被收录于专栏:程序小小事

前面两篇文章已经把父类和子类关系型模式说完了。

今天开始介绍普通类之间构成的关系型设计模式。首先来说说观察者模式

前言

还是这张概总图。

在现实世界中,许多对象都不是独立存在的。其中一个对象的行为发生改变可能会导致一个或者多个其他对象的行为也发生改变。

例如:

  • 某种商品的物价上涨时会导致部分商家高兴,而消费者伤心;
  • 当我们开车到交叉路口时,遇到红灯会停,遇到绿灯会行;
  • 再如关注了【程序视点】微信公众号服务后,当小二哥发布消息时,大家就可以收到推送消息,取消关注就收不到推送消息。

这样的例子还有很多……

这些情况下,如果用观察者模式来实现就非常方便。

简介

观察者模式是对象的行为模式。有的地方称作的发布-订阅模式模型-视图模式源-监听器模式从属者模式等,当你看到这种叫法时,不要觉得陌生,它们都是观察者模式。

观察者模式是关于多个对象想知道一个对象中数据变化情况的一种成熟的模式

它可以实现对象之间的松耦合通信,当一个对象发生变化时通知其它相关的对象做出相应的响应。

主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。

结构剖析

观察者模式中有一个称作“主题”的对象和若干个称作“观察者”的对象,“主题”和“观察者”间是一种一对多的依赖关系,当“主题”的状态发生变化时,所有“观察者”都得到通知。

观察者模式的结构中包含四种角色:

(1)主题(Subject):主题是一个接口,该接口规定了具体主题需要实现的方法,比如,添加、删除观察者以及通知观察者更新数据的方法。

(2)观察者(Observer):观察者是一个接口,该接口规定了具体观察者用来更新数据的方法。

(3)具体主题(ConcreteSubject):具体主题是实现主题接口类的一个实例,该实例包含有可以经常发生变化的数据。具体主题需使用一个集合,比如ArrayList,存放观察者的引用,以便数据变化时通知具体观察者。

(4)具体观察者(ConcreteObserver):具体观察者是实现观察者接口类的一个实例。具体观察者包含有可以存放具体主题引用的主题接口变量,以便具体观察者让具体主题将自己的引用添加到具体主题的集合中,使自己成为它的观察者,或让这个具体主题将自己从具体主题的集合中删除,使自己不再是它的观察者。

实现示例

我们现在来简单实现下公众号发送推文,大家就能接受消息的这一场景。

1、定义一个抽象被观察者接口--主题

代码语言:javascript
复制
public interface Subject {
 
   public void registerObserver(Observer o);
   public void removeObserver(Observer o);
   public void notifyObserver();
 
}

2、定义一个抽象观察者接口 -- 观察者

代码语言:javascript
复制
public interface Observer {
 
 public void update(String message);
 
}

3、定义具体的被观察主题 -- 具体主题

实现了 Subject 接口,同时有一个List集合,用以保存注册的观察者,等需要通知观察者时,遍历该集合即可。

代码语言:javascript
复制
public class WechatServer implements Subject {
 
 private List<Observer> list;
 private String message;
 
 public WechatServer() {
  list = new ArrayList<Observer>();
 }
 
 @Override
 public void registerObserver(Observer o) {
  // TODO Auto-generated method stub
  list.add(o);
 }
 
 @Override
 public void removeObserver(Observer o) {
  // TODO Auto-generated method stub
  if (!list.isEmpty()) {
   list.remove(o);
  }
 }
 
 @Override
 public void notifyObserver() {
  // TODO Auto-generated method stub
  for (Observer o : list) {
   o.update(message);
  }
 }
 
 public void setInfomation(String s) {
  this.message = s;
  System.out.println("程序视点更新消息: " + s);
  // 消息更新,通知所有观察者
  notifyObserver();
 }
 
}

4、定义具体观察者,微信公众号的具体观察者为用户User

代码语言:javascript
复制
public class User implements Observer {
 
 private String name;
 private String message;
 
 public User(String name) {
  this.name = name;
 }
 
 @Override
 public void update(String message) {
  this.message = message;
  read();
 }
 
 public void read() {
  System.out.println(name + " 收到推送消息: " + message);
 }
 
}

🆗,让我们来测试下

代码语言:javascript
复制
public class MainTest {
 
  public static void main(String[] args) {
   
         WechatServer server = new WechatServer();
         
         Observer userZhang = new User("ZhangSan");
         Observer userLi = new User("LiSi");
         Observer userWang = new User("WangWu");
         
         server.registerObserver(userZhang);
         server.registerObserver(userLi);
         server.registerObserver(userWang);
         server.setInfomation("【程序视点】为大家不定时推送消息!");
         
         System.out.println("----------------------------------------------");
         server.removeObserver(userZhang);
         server.setInfomation("【程序视点】的读者是世界上最好的读者!");
         
     }
}

输出:程序视点更新消息:【程序视点】为大家不定时推送消息! ZhangSan 收到推送消息:【程序视点】为大家不定时推送消息! LiSi 收到推送消息:【程序视点】为大家不定时推送消息! WangWu 收到推送消息:【程序视点】为大家不定时推送消息! ----------------------------------------------程序视点更新消息:程序视点】的读者是世界上最好的读者! ZhangSan 收到推送消息:程序视点】的读者是世界上最好的读者! LiSi 收到推送消息:程序视点】的读者是世界上最好的读者! WangWu 收到推送消息:程序视点】的读者是世界上最好的读者!

小结

观察者模式理解起来比较简单。主要注意以下几点:

  • 要明确谁是观察者,谁是被观察者。明白了关注对象,问题也就清楚了;
  • 具体的被观察者在发送广播通知时,无须指定具体观察者;观察者可以自己决定是否要订阅通知;
  • 被观察者至少有三个方法:添加监听者、删除监听者和通知监听者;
  • 观察者至少有一个方法:更新方法,即对通知的处理方式。

观察者模式的应用场景如下:

  • 关联行为场景。需要注意的是,关联行为是可拆分的,而不是“组合”关系。也就说的是不同对象的行为之间的关系。

ps:当一个对象的行为改变时,需要改变其它的对象的行为的情况。

  • 事件多级触发场景。

ps:一个事件发生,引起多个其他事件变化的情况。

  • 跨系统的消息交换场景。一个对象仅需要将自己的更新通知给其它对象而不需要知道其它对象细节,如消息队列、事件总线的处理机制。

ps:即当一个对象必须通知其他对象,但是却不能与其他对象造成紧密耦合的情况。

通过上面的分析,我们很容易发现观察者模式的优点:解除耦合。让耦合的双方都依赖于抽象,从而使得各自的变换都不会影响另一边的变换。

那有没有什么缺点呢?

在应用观察者模式时需要考虑一下开发效率和运行效率的问题,程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂。

在Java中消息的通知一般是顺序执行,那么一个观察者卡顿,会影响整体的执行效率。在这种情况下,解决方法一般会采用异步实现

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-06-08 08:08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序视点 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 简介
  • 结构剖析
  • 实现示例
  • 小结
相关产品与服务
消息队列 CMQ
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档