行为型模式-协作与交互机制

行为型模式聚焦于对象间的行为交互,通过规范对象协作方式提升系统的灵活性与可扩展性。在分布式系统中,由于多节点异步通信、网络不可靠性及状态一致性挑战,行为型模式需针对分布式特性进行适应性设计。本文从观察者、策略、命令、责任链、状态五大核心行为型模式出发,系统解析其在分布式场景下的演化与实践。

一、观察者模式:分布式事件的发布 - 订阅机制

1.1 模式核心与分布式适配

观察者模式通过发布 - 订阅机制实现对象间的松耦合通信,在分布式系统中演变为跨节点的事件驱动架构(EDA),解决节点间异步通知问题。

1. 基于消息队列的分布式观察者
// 事件定义(跨节点传输) 
public class OrderEvent implements Serializable { private String eventId; private Long orderId; private OrderStatus status; private LocalDateTime timestamp; // getters/setters 
} // 抽象主题(事件发布者) 
public interface EventPublisher { void publish(OrderEvent event); 
} // 具体发布者(订单服务) 
public class OrderService implements EventPublisher { @Autowired private KafkaTemplate<String, OrderEvent> kafkaTemplate; @Override public void publish(OrderEvent event) { // 发布事件到Kafka主题 kafkaTemplate.send("order-events", event.getOrderId().toString(), event); } // 订单状态变更时发布事件 public void updateStatus(Long orderId, OrderStatus status) { OrderEvent event = new OrderEvent(UUID.randomUUID().toString(), orderId, status, LocalDateTime.now()); publish(event); } 
} 
// 抽象观察者(事件订阅者) 
public interface EventSubscriber { void onEvent(OrderEvent event); 
} // 具体观察者(库存服务) 
public class InventorySubscriber implements EventSubscriber { @KafkaListener(topics = "order-events") @Override public void onEvent(OrderEvent event) { if (event.getStatus() == OrderStatus.PAID) { // 订单支付后扣减库存 inventoryService.deduct(event.getOrderId()); } } 
} // 具体观察者(积分服务) 
public class PointSubscriber implements EventSubscriber { @KafkaListener(topics = "order-events") @Override public void onEvent(OrderEvent event) { if (event.getStatus() == OrderStatus.PAID) { // 订单支付后增加积分 pointService.add(event.getOrderId()); } } 
} 
2. 分布式场景关键特性
  • 异步解耦:发布者无需知道订阅者存在(如订单服务不依赖库存 / 积分服务),降低节点耦合。

  • 可靠性保障:通过消息队列的持久化(如 Kafka 的日志存储)确保事件不丢失,应对节点宕机。

  • 广播能力:同一事件可被多个订阅者消费(如订单支付事件同时通知库存、积分、物流服务)。

1.2 与传统观察者的核心区别

维度单体观察者模式分布式观察者模式(事件驱动)
通信方式内存直接调用消息队列异步通信(跨节点)
可靠性依赖本地调用,失败直接抛出异常消息重试机制,支持死信队列处理失败事件
订阅管理代码中直接注册观察者通过消息队列主题动态订阅(无需代码变更)

二、策略模式:分布式场景的动态算法切换

2.1 模式核心与负载均衡策略

策略模式通过封装不同算法实现动态切换,在分布式系统中广泛应用于负载均衡、路由策略、序列化方式选择等场景。

1. 分布式负载均衡的策略设计
// 策略接口(负载均衡算法) 
public interface LoadBalanceStrategy { String selectInstance(List<String> instances); 
} // 具体策略1:轮询 
public class RoundRobinStrategy implements LoadBalanceStrategy { private AtomicInteger index = new AtomicInteger(0); @Override public String selectInstance(List<String> instances) { if (instances.isEmpty()) return null; int i = index.getAndIncrement() % instances.size(); return instances.get(i); } 
} 
// 具体策略2:权重 
public class WeightedStrategy implements LoadBalanceStrategy { @Override public String selectInstance(List<String> instances) { // 假设实例格式为"ip:port:weight",解析权重并选择 int totalWeight = instances.stream() .mapToInt(inst -> Integer.parseInt(inst.split(":")[2])) .sum(); int random = new Random().nextInt(totalWeight); int current = 0; for (String inst : instances) { int weight = Integer.parseInt(inst.split(":")[2]); current += weight; if (current > random) { return inst; } } return instances.get(0); } 
} // 策略上下文(负载均衡器) 
public class LoadBalancer { private LoadBalanceStrategy strategy; // 动态设置策略(如从配置中心获取) public void setStrategy(LoadBalanceStrategy strategy) { this.strategy = strategy; } public String chooseInstance(String serviceName) { // 从注册中心获取服务实例列表 List<String> instances = serviceDiscovery.getInstances(serviceName); return strategy.selectInstance(instances); } 
} // 使用示例 
public class ServiceConsumer { public void invokeService() { LoadBalancer balancer = new LoadBalancer(); // 从配置动态选择策略(如"weighted") String strategyType = Config.get("loadbalance.strategy"); balancer.setStrategy(StrategyFactory.create(strategyType)); String instance = balancer.chooseInstance("order-service"); // 调用选中的实例 } 
} 
2. 分布式场景价值
  • 动态适配:根据集群状态切换策略(如低负载时用轮询,高负载时用权重策略)。

  • 灰度发布:通过策略路由部分流量到新版本实例(如GrayStrategy只将 10% 流量路由到新实例)。

三、命令模式:分布式任务的异步执行与重试

3.1 模式核心与分布式命令

命令模式通过封装请求为对象,实现请求的异步执行、日志记录与重试,在分布式系统中演变为跨节点任务调度机制。

1. 分布式任务的命令设计
// 命令接口 public interface DistributedCommand extends Serializable { String getCommandId(); // 唯一命令ID(用于幂等性) CommandResult execute(); // 执行命令 CommandResult compensate(); // 补偿命令(失败时执行) 
} 
// 具体命令:订单支付命令 
public class PaymentCommand implements DistributedCommand { private String commandId; private Long orderId; private BigDecimal amount; @Override public CommandResult execute() { try { // 调用支付服务 paymentService.pay(orderId, amount); return CommandResult.success(); } catch (Exception e) { return CommandResult.failure(e.getMessage()); } } @Override public CommandResult compensate() { // 支付失败时执行退款 return paymentService.refund(orderId) ? CommandResult.success() : CommandResult.failure("退款失败"); } // getters/setters 
} // 命令调用者(任务调度器) 
public class CommandScheduler { @Autowired private KafkaTemplate<String, DistributedCommand> kafkaTemplate; @Autowired private CommandRepository repository; // 命令日志存储 // 发送命令到执行节点 public void schedule(DistributedCommand command) { // 保存命令日志(用于重试和恢复) repository.save(new CommandLog(command.getCommandId(), command, CommandStatus.PENDING)); // 发送到命令主题 kafkaTemplate.send("command-topic", command.getCommandId(), command); } // 处理命令结果 public void handleResult(String commandId, CommandResult result) { CommandLog log = repository.findById(commandId); if (result.isSuccess()) { log.setStatus(CommandStatus.SUCCESS); } else { log.setStatus(CommandStatus.FAILED); // 失败重试(最多3次) if (log.getRetryCount() < 3) { log.incrementRetryCount(); kafkaTemplate.send("command-topic", commandId, log.getCommand()); } } repository.update(log); } 
} // 命令执行者(工作节点) 
public class CommandWorker { @KafkaListener(topics = "command-topic") public void executeCommand(ConsumerRecord<String, DistributedCommand> record) { DistributedCommand command = record.value(); CommandResult result = command.execute(); // 发送执行结果 commandScheduler.handleResult(command.getCommandId(), result); } 
} 
2. 分布式场景优势
  • 异步执行:命令通过消息队列异步发送到工作节点,调用者无需等待执行完成。

  • 故障恢复:命令日志记录执行状态,节点宕机后可从日志恢复未完成命令。

  • 幂等设计:通过commandId确保重复执行(如消息重试)不会产生副作用。

四、责任链模式:分布式请求的链式处理

4.1 模式核心与 API 网关过滤链

责任链模式通过多个处理器依次处理请求,在分布式系统中广泛应用于 API 网关的请求过滤、分布式事务的阶段处理等场景。

1. API 网关的责任链设计
// 处理器接口 
public interface GatewayFilter { void doFilter(GatewayRequest request, GatewayResponse response, GatewayFilterChain chain); 
} // 具体过滤器1:认证过滤 
public class AuthFilter implements GatewayFilter { @Override public void doFilter(GatewayRequest request, GatewayResponse response, GatewayFilterChain chain) { String token = request.getHeader("Authorization"); if (token == null || !authService.validate(token)) { response.setStatusCode(401); response.setBody("Unauthorized"); return; // 终止链 } chain.doFilter(request, response); // 继续下一个过滤器 } 
} // 具体过滤器2:限流过滤 
public class RateLimitFilter implements GatewayFilter { private RedisTemplate<String, Integer> redisTemplate; @Override public void doFilter(GatewayRequest request, GatewayResponse response, GatewayFilterChain chain) { String clientIp = request.getClientIp(); String key = "rate_limit:" + clientIp; // 使用Redis实现限流 Long count = redisTemplate.opsForValue().increment(key, 1); if (count == 1) { redisTemplate.expire(key, 1, TimeUnit.MINUTES); } if (count > 100) { // 每分钟最多100次请求 response.setStatusCode(429); response.setBody("Too Many Requests"); return; } chain.doFilter(request, response); } 
} // 过滤器链 
public class DefaultGatewayFilterChain implements GatewayFilterChain { private List<GatewayFilter> filters; private int index = 0; public DefaultGatewayFilterChain(List<GatewayFilter> filters) { this.filters = filters; } @Override public void doFilter(GatewayRequest request, GatewayResponse response) { if (index < filters.size()) { GatewayFilter filter = filters.get(index++); filter.doFilter(request, response, this); } } 
} // API网关 
public class ApiGateway { public GatewayResponse handleRequest(GatewayRequest request) { GatewayResponse response = new GatewayResponse(); // 构建过滤器链(认证→限流→路由) List<GatewayFilter> filters = Arrays.asList( new AuthFilter(), new RateLimitFilter(), new RouteFilter() ); new DefaultGatewayFilterChain(filters).doFilter(request, response); return response; } 
} 
2. 分布式场景价值
  • 横切逻辑复用:认证、限流等逻辑集中在网关,无需每个服务重复实现。

  • 动态扩展:通过配置中心动态增删过滤器(如临时添加维护模式过滤器)。

五、状态模式:分布式系统的状态机管理

5.1 模式核心与订单状态流转

状态模式通过封装对象状态及其转换逻辑,在分布式系统中用于管理跨节点的状态一致性(如订单状态、工作流状态)。

1. 分布式订单状态机
// 状态接口 
public interface OrderState { void pay(OrderContext context); // 支付操作 void ship(OrderContext context); // 发货操作 void complete(OrderContext context); // 完成操作 OrderStatus getStatus(); // 获取当前状态 } // 具体状态:待支付 
public class PendingState implements OrderState { @Override public void pay(OrderContext context) { // 状态转换:待支付→已支付 context.setState(new PaidState()); // 发布状态变更事件(通知其他节点) context.publishEvent(OrderStatus.PAID); } @Override public void ship(OrderContext context) { throw new IllegalStateException("未支付订单不能发货"); } @Override public void complete(OrderContext context) { throw new IllegalStateException("未支付订单不能完成"); } @Override public OrderStatus getStatus() { return OrderStatus.PENDING; } } 
// 具体状态:已支付(其他状态略) 
public class PaidState implements OrderState { /* 实现发货等操作 */ } 
// 上下文:订单状态管理器 public class OrderContext { private OrderState currentState; private Long orderId; private EventPublisher eventPublisher; public OrderContext(Long orderId) { this.orderId = orderId; this.currentState = new PendingState(); // 初始状态 } // 委托状态操作 public void pay() { currentState.pay(this); } public void ship() { currentState.ship(this); } public void complete() { currentState.complete(this); } // 发布状态事件(跨节点同步) public void publishEvent(OrderStatus status) { eventPublisher.publish(new OrderEvent(orderId, status)); } // 设置状态(仅允许状态内部调用) void setState(OrderState state) { this.currentState = state; } } // 使用示例 
public class OrderController { @PostMapping("/orders/{id}/pay") public void payOrder(@PathVariable Long id) { OrderContext context = orderContextManager.get(id); context.pay(); // 状态转换由状态机管理 } 
} 
2. 分布式场景挑战与解决
  • 状态一致性:通过事件发布同步状态变更(如订单服务状态变更后,通知库存服务)。

  • 并发安全:状态转换加分布式锁(如 Redis 锁),防止并发操作导致状态错乱。

六、面试高频问题深度解析

6.1 基础概念类问题

Q:分布式环境下的观察者模式与传统观察者模式有何本质区别?如何保证事件不丢失?

A:

  • 本质区别

    传统观察者是进程内同步调用(如内存中的发布 - 订阅),分布式观察者基于消息队列异步通信,跨节点、跨进程。

  • 不丢失保证

  1. 消息持久化:Kafka 将消息写入磁盘,确保 broker 宕机后数据不丢失。

  2. 确认机制:消费者处理完成后发送 ACK(如 Kafka 的 offset 提交),未确认则重试。

  3. 死信队列:多次重试失败的事件进入死信队列,人工干预处理。

Q:策略模式在分布式负载均衡中的应用?如何动态切换负载均衡策略?

A:

  • 应用场景

    策略模式封装轮询、权重、IP 哈希等负载均衡算法,LoadBalancer通过setStrategy()动态选择算法。

  • 动态切换

  1. 配置中心(如 Nacos)存储策略类型(如weighted)。

  2. 客户端监听配置变更,调用setStrategy()更新策略。

  3. 示例:流量高峰时切换到权重策略(优先调度到高配节点),低谷时用轮询策略。

6.2 实战设计类问题

Q:如何用责任链模式设计一个支持多租户的 API 网关权限系统?

A:

  1. 过滤器链设计
  • TenantFilter:解析请求中的租户 ID,验证租户合法性。

  • AuthFilter:验证租户内用户的令牌有效性。

  • PermissionFilter:检查用户是否有权限访问当前接口(结合租户 + 用户角色)。

  • RateLimitFilter:按租户限制 API 调用频率。

  1. 执行逻辑

    网关接收请求后,依次执行过滤器链,任何过滤器失败则返回对应错误(如 401/403)。

  2. 租户隔离

    每个过滤器通过request.getTenantId()获取租户上下文,确保权限校验在租户维度隔离。

Q:分布式状态机如何保证跨节点的状态一致性?

A:

  1. 状态事件同步:状态变更时发布全局事件(如OrderStatusChangedEvent),所有节点消费事件更新本地状态。

  2. 分布式锁:状态转换操作加锁(如 Redis 锁),防止并发修改导致状态冲突。

  3. 状态校验:节点启动时从事件日志重建状态(如从 Kafka 消费历史事件恢复最新状态)。

总结:行为型模式的分布式设计原则

核心选型策略

分布式场景推荐模式核心解决问题
跨节点异步通知观察者模式(消息队列)节点解耦,事件驱动协作
动态算法切换(负载均衡等)策略模式算法与使用分离,支持动态适配
分布式任务调度与重试命令模式任务异步执行,支持补偿与幂等性
网关过滤、请求处理链责任链模式横切逻辑复用,动态扩展过滤器
跨节点状态流转(订单等)状态模式状态转换逻辑封装,保证状态一致性

分布式适配要点

  1. 异步优先:尽量采用异步通信(消息队列)减少节点阻塞,应对网络延迟。

  2. 幂等设计:所有跨节点操作需保证幂等性(如命令 ID、事件 ID),防止重试导致副作用。

  3. 容错机制:结合重试、超时控制、熔断降级,应对网络分区与节点故障。

通过掌握行为型模式在分布式系统中的适配逻辑,不仅能在面试中清晰解析跨节点协作问题,更能在实际架构中设计松耦合、高可用的分布式系统,体现高级程序员对复杂系统的设计能力。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/915923.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/915923.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

spring boot 整合 Spring Cloud、Kafka 和 MyBatis菜鸟教程

环境准备确保项目中已引入 Spring Boot、Spring Cloud、Kafka 和 MyBatis 的依赖。以下是一个典型的 Maven 依赖配置&#xff1a;<dependencies><!-- Spring Boot Starter --><dependency><groupId>org.springframework.boot</groupId><artif…

20 BTLO 蓝队靶场 Sticky Situation 解题记录

难度&#xff1a;5/10考察技能: Windows admin, Autopsy 使用场景&#xff1a;分析USB设备使用情况Autopsy使用注意&#xff1a;用管理员打开&#xff0c;在实际分析时注意先复制一个镜像文件&#xff0c;保存好原文件常用的Windows USB 取证的位置:Windows XP:Registry Key: U…

安装及配置Go语言开发环境与VSCode集成指南

安装Go语言开发 安装Go语言开发环境是第一步。访问Go官网&#xff0c;下载适合操作系统的安装包&#xff0c;如果进不去可以访问Go官方镜像站。 根据自己的系统选择对应的安装包&#xff0c;我这边是Windows系统就点击安装第一个即可。 点击下一步即可。 验证安装是否成功可以…

专题:2025微短剧行业生态构建与跨界融合研究报告|附100+份报告PDF汇总下载

原文链接&#xff1a; https://tecdat.cn/?p43384 分析师&#xff1a;Boyu Wang 在此对 Boyu Wang 对本文所作的贡献表示诚挚感谢&#xff0c;他在武汉大学完成了数据科学与大数据技术专业的学习。擅长 R 语言、Python、机器学习、数据可视化。 中国短视频行业在经历爆发式增…

配置NGINX

Nginx环境配置与前端VUE部署安装nginx&#xff1a;命令sudo yum update && sudo yum install nginx部署:拷贝前端到目录/home/publish/idasweb/下修改nginx配置&#xff1a;进入到/etc/nginx目录下&#xff0c;修改nginx.conf中user www-data为user root&#xff0c;不…

MySQL深度理解-MySQL索引优化

1.Order by与Group by优化1.1Case1employees表中建立了name&#xff0c;position和age索引&#xff0c;并且使用了order by age进行排序操作&#xff1a;EXPLAIN SELECT * FROM employees WHERE name LiLei and position dev order by age最终explain的结果发现使用了idx_nam…

「Linux命令基础」用户和用户组实训

用户与用户组关系管理 在Linux系统中,用户和用户组的关系就像班级里的学生和小组。一个用户可以同时属于多个组,这种灵活的成员关系为权限管理提供了便利。创建用户时,系统会自动生成一个与用户同名的主组,这个组会成为用户创建文件时的默认属组。 理解用户和用户组的关系…

Https以及CA证书

目录 1. 什么是 HTTPS 通信机制流程 证书验证过程 CA证书 浏览器如何校验证书合法性呢&#xff1f; 1. 什么是 HTTPS HTTP 加上加密处理和认证以及完整性保护后即是 HTTPS。 它是为了解决 HTTP 存在的安全性问题&#xff0c;而衍生的协议&#xff0c;那使用 HTTP 的缺点有…

数字图像处理(四:图像如果当作矩阵,那加减乘除处理了矩阵,那图像咋变):从LED冬奥会、奥运会及春晚等等大屏,到手机小屏,快来挖一挖里面都有什么

数字图像处理&#xff08;四&#xff09;三、&#xff08;准备工作&#xff1a;玩具咋玩&#xff09;图像以矩阵形式存储&#xff0c;那矩阵一变、图像立刻跟着变&#xff1f;原图发挥了钞能力之后的图上述代码包含 10 个图像处理实验&#xff0c;每个实验会生成对应处理后的图…

SpringBoot航空订票系统的设计与实现

文章目录前言详细视频演示具体实现截图后端框架SpringBoot持久层框架Hibernate成功系统案例&#xff1a;代码参考数据库源码获取前言 博主介绍:CSDN特邀作者、985高校计算机专业毕业、现任某互联网大厂高级全栈开发工程师、Gitee/掘金/华为云/阿里云/GitHub等平台持续输出高质…

2025年PostgreSQL 详细安装教程(windows)

前言 PostgreSQL 是一个功能强大的开源关系型数据库管理系统(ORDBMS)&#xff0c;以下是对它的全面介绍&#xff1a; 基本概况 名称&#xff1a;通常简称为 "Postgres" 类型&#xff1a;对象-关系型数据库管理系统 许可&#xff1a;开源&#xff0c;采用类MIT许可…

Java日志按天切分方法

使用 Logrotate&#xff08;推荐&#xff09;Logrotate 是 Linux 系统自带的日志管理工具&#xff0c;支持自动切割、压缩和删除旧日志。步骤&#xff1a;创建 Logrotate 配置文件在 /etc/logrotate.d/ 下新建配置文件&#xff08;如 java-app&#xff09;&#xff1a;sudo nan…

进阶向:基于Python的本地文件内容搜索工具

概述 大家好&#xff01;今天我们将一起学习如何用Python创建一个简单但强大的本地文件内容搜索工具。这个工具特别适合处理大量文本文件时的快速检索需求。 为什么要学习这个工具 如果你刚接触编程&#xff0c;完全不用担心&#xff01;我会从零开始讲解&#xff0c;确保每…

多模态AI的可解释性

多模态AI的可解释性挑战 在深入探讨解决方案之前&#xff0c;首先需要精确地定义问题。多模态模型因其固有的复杂性&#xff0c;其内部决策过程对于人类观察者而言是不透明的。 模态融合机制 (Modal Fusion Mechanism)&#xff1a;模型必须将来自不同来源&#xff08;如图像和文…

MySQL深度理解-MySQL事务优化

1.什么是事务事务就是进行多个操作&#xff0c;要么同时执行成功&#xff0c;要么同时执行失败。2.事务的特性 - ACID特性2.1原子性Atomicity原子性&#xff08;Atomicity&#xff09;&#xff1a;当前事务的操作要么同时成功&#xff0c;要么同时失败。原子性由undo log日志来…

2025小学所有学习科目的全部版本电子教材

2025春小学最新课本-新版电子教材【文末自行获取全部资料~】 小学语文&#xff1a; 小学数学&#xff1a; 小学英语&#xff1a; 小学科学&#xff1a; 小学道德与法治&#xff1a; 小学劳动技术&#xff1a; 小学美术&#xff1a; 小学书法练习指导&#xff1a; 小学体育与健康…

华为视觉算法面试30问全景精解

华为视觉算法面试30问全景精解 ——技术引领 工程极致 智能未来:华为视觉算法面试核心考点全览 前言 华为作为全球领先的ICT(信息与通信技术)解决方案供应商,在智能终端、云计算、智慧城市、自动驾驶、工业互联网等领域持续推动视觉AI的创新与产业落地。华为视觉算法岗…

【Anaconda】Conda 虚拟环境打包迁移教程

Conda 虚拟环境打包迁移教程本文介绍如何使用 conda-pack 将 Conda 虚拟环境打包&#xff0c;并在另一台电脑上快速迁移、部署。0. 安装 conda-pack conda-pack 并非 Conda 默认自带工具&#xff0c;首次使用前必须手动安装。以下两种安装方式任选其一即可&#xff1a; ✅ 方法…

matrix-breakout-2-morpheus靶机通关教程

目录 一、信息搜集 二、尝试GetShell 三、反弹Shell 一、信息搜集 首先搜集信息&#xff0c;观察页面。 发现什么都没有&#xff0c;我们先来发现一下它的IP以及开放的端口。首先我们观察一下它的网络模式是怎么样的&#xff0c;来确定IP段。 可以发现他是NAT模式&#xff0…

深入思考【九九八十一难】的意义,试用歌曲能否解释

1. 《平凡之路》- 朴树契合点&#xff1a;前半生追求明白&#xff1a;“我曾经失落失望失掉所有方向&#xff0c;直到看见平凡才是唯一的答案”。后半生修行糊涂&#xff1a;“时间无言&#xff0c;如此这般&#xff0c;明天已在眼前”。对过去的释然与对未来的随缘&#xff0c…