笔头云 笔头云
首页
设计模式
SQL教程
Redis
归档
关于
友链

笔头云

非淡泊无以明志,非宁静无以致远。
首页
设计模式
SQL教程
Redis
归档
关于
友链
  • 设计原则
  • 设计模式
  • 单例模式
  • 工厂模式
  • 建造者模式
  • 原型模式
  • 适配器模式
  • 代理模式
  • 装饰器模式
  • 门面模式
  • 桥接模式
  • 享元模式
  • 组合模式
  • 策略模式
  • 模板方法模式
  • 观察者模式
    • 定义
    • 结构
    • 优点
    • 应用场景
    • 示例代码1
    • 示例代码2
  • 责任链模式
  • 状态模式
  • 迭代器模式
  • 访问者模式
  • 中介模式
  • 命令模式
  • 解释器模式
  • 备忘录模式
  • 设计模式
笔头云
2023-10-20
目录

观察者模式

# 观察者模式

观察者模式类似于生活中关注微信公众号、明星微博等,当公众号或明星发布信息时,粉丝就会收到信息。

# 定义

观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。

# 结构

主题(Subject):也称为被观察者或可观察对象,它是具有状态并且可以被观察的对象。主题维护一个观察者列表,并提供方法用于添加、删除和通知观察者。当主题的状态发生变化时,它会通知所有观察者。
观察者(Observer):观察者是依赖于主题的对象,当主题的状态发生变化时,观察者会接收到相应的通知,并根据通知进行更新。观察者一般定义了一个更新方法,用于接收主题的通知。

观察者模式

- img: https://bitouyun.com/images/design-pattern/observer.png
  link: https://bitouyun.com/images/design-pattern/observer.png
  name: 观察者模式
1
2
3

# 优点

开闭原则。 你无需修改发布者代码就能引入新的订阅者类 (如果是发布者接口则可轻松引入发布者类)。

# 应用场景

当一个对象状态的改变需要改变其他对象, 或实际对象是事先未知的或动态变化的时, 可使用观察者模式。

# 示例代码1

场景1

使用观察者模式实现了一对多的消息通知机制,当主题状态发生变化时,通知所有观察者,观察者都能收到相应的通知并进行处理。

    /**
     * 主题接口
     * 被观察者或可观察对象,它是具有状态并且可以被观察的对象。
     */
    public interface Subject {
        // 注册观察者
        void registerObserver(Observer observer);
    
        // 移除观察者
        void removeObserver(Observer observer);
    
        // 通知所有观察者
        void notifyObservers(String message);
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    /**
     * 具体主题类
     * 实现主题接口,维护一个观察者列表,并提供了注册、移除和通知观察者的方法。
     */
    public class ConcreteSubject implements Subject {
        // 维护了一个观察者列表
        private List<Observer> observers = new ArrayList<>();
    
        // 注册观察者
        @Override
        public void registerObserver(Observer observer) {
            observers.add(observer);
        }
    
        // 移除观察者
        @Override
        public void removeObserver(Observer observer) {
            observers.remove(observer);
        }
    
        // 通知所有观察者
        @Override
        public void notifyObservers(String message) {
            observers.forEach(observer -> {
                observer.update(message);
            });
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    /**
     * 观察者接口
     * 观察者是依赖于主题的对象,当主题的状态发生变化时,观察者会接收到相应的通知,并根据通知进行更新。观察者一般定义了一个更新方法,用于接收主题的通知
     */
    public interface Observer {
        // 更新方法,处理接收到的消息
        void update(String message);
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    /**
     * 具体观察者
     * 实现观察者接口,定义了update方法来处理接收到的消息。
     */
    @Slf4j
    public class ConcreteObserver implements Observer {
        // 观察者名称
        private String name;
    
        public ConcreteObserver(String name) {
            this.name = name;
        }
    
        @Override
        public void update(String message) {
            log.info("{} 接收消息:{}", name, message);
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    /**
     * 测试类
     * 使用观察者模式实现了一对多的消息通知机制,当主题状态发生变化时,通知所有观察者,观察者都能收到相应的通知并进行处理。
     */
    @Slf4j
    public class Client {
    
        public static void main(String[] args) {
            // 创建主题
            Subject subject = new ConcreteSubject();
    
            // 创建观察者
            Observer observer1 = new ConcreteObserver("观察者1");
            Observer observer2 = new ConcreteObserver("观察者2");
            Observer observer3 = new ConcreteObserver("观察者3");
    
            // 注册观察者
            subject.registerObserver(observer1);
            subject.registerObserver(observer2);
            subject.registerObserver(observer3);
    
            // 发布消息
            log.info("发布消息------");
            subject.notifyObservers("你好,观察者!");
    
            // 移除观察者
            subject.removeObserver(observer1);
    
            // 发布消息
            log.info("移除观察者,再次发布消息------");
            subject.notifyObservers("再见,观察者!");
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    // Make sure to add code blocks to your code group

    # 示例代码2

    场景2

    网上购物,顾客下单后除了要记录订单信息外,还需要增加积分、发送下单短信等,
    主业务中只保存订单信息,增加积分、发送短信让观察者去实现,当保存订单信息后通知观察者添加积分记录、发送短信。 主业务开启事务,如过不想让子业务影响主业务,则捕获子业务的异常。

      public class OrderEvent extends ApplicationEvent {
      
        private Order order;
      
        public OrderEvent(Object source, Order order) {
          super(source);
          this.order = order;
        }
      
        public Order getOrder() {
          return order;
        }
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      @Slf4j
      @Component
      public class OrderListener implements ApplicationListener<OrderEvent> {
      
        @Resource
        private PointRecordRepository pointRecordRepository;
      
        @Override
        @Transactional
        public void onApplicationEvent(OrderEvent orderEvent) {
          log.info("接收到订单消息:{}", orderEvent);
          // 增加积分记录
          PointRecord pointRecord = new PointRecord();
          pointRecord.setUserId(orderEvent.getOrder().getUserId()); // 用户id
          pointRecord.setOrderNo(orderEvent.getOrder().getOrderNo()); // 订单编号
          pointRecord.setPoint(orderEvent.getOrder().getAmount()); // 积分
          this.pointRecordRepository.insert(pointRecord);
          // 发送短信
          log.info("您的订单已创建,我们将尽快给您发货");
        }
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      @Slf4j
      @Service
      public class OrderServiceImpl implements OrderService {
      
        @Resource
        private OrderRepository orderRepository;
        @Resource
        private ApplicationContext applicationContext;
      
        @Override
        @Transactional
        public String buy() {
          log.info("客户下单");
          // 1.创建订单
          Order order = new Order();
          String orderNo = DateUtil.format(new Date(), DatePattern.PURE_DATETIME_MS_PATTERN);
          order.setOrderNo(orderNo); // 订单号
          order.setUserId(IdUtil.fastSimpleUUID()); // 用户id
          order.setAmount(1000); // 订单金额
          this.orderRepository.insert(order);
          // 2.其它业务逻辑
          applicationContext.publishEvent(new OrderEvent(this, order)); // 积分记录
          applicationContext.publishEvent(new MessageEvent(order)); // 发送消息
          return "购买成功";
        }
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      @Slf4j
      @RestController
      @RequestMapping(value = "/api")
      public class OrderController {
      
        private final OrderService orderService;
      
        public OrderController(OrderService orderService) {
          this.orderService = orderService;
        }
        
        @GetMapping(value = "/order/buy")
        public ResponseEntity<?> buy() {
          log.debug("请求下单");
          this.orderService.buy();
          return ResponseEntity.ok("下单成功");
        }
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      @Data
      @AllArgsConstructor
      public class MessageEvent {
        private Order order;
      }
      
      1
      2
      3
      4
      5
      // @Async // 需要异步放开注释,并在启动类增加@EnableAsync注解
      @Slf4j
      @Component
      public class MessageListener {
          @EventListener(MessageEvent.class)
          public void sendMessage(MessageEvent messageEvent) {
              log.info("发送短信,订单编号:{}, 积分:{}", messageEvent.getOrder().getOrderNo(), messageEvent.getOrder().getAmount());
          }
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      // Make sure to add code blocks to your code group
      #行为型模式#设计模式
      上次更新: 2023/11/17, 09:38:49
      模板方法模式
      责任链模式

      ← 模板方法模式 责任链模式→

      最近更新
      01
      FRP内网穿透docker部署 工具
      05-07
      02
      Office Util办公工具 工具
      01-14
      03
      Git常用命令
      01-16
      更多文章>
      Theme by Vdoing | Copyright © 2023-2025 鲁ICP备2023014898号 公安备案号:37020302372159
      • 跟随系统
      • 浅色模式
      • 深色模式
      • 阅读模式
      ×