这 5 个设计模式在微服务架构中最好用——《Head First 设计模式》精读笔记
为什么是这 5 个
GoF 23 个设计模式中,很多在单体应用中很好用,但在微服务架构中变得不那么重要(比如 Flyweight、Bridge)。而有些模式在分布式场景下反而更加关键。
经过多个微服务项目的实战积累,以下 5 个模式的使用频率最高:
| 模式 | 类型 | 微服务核心场景 |
|------|------|--------------|
| 策略模式(Strategy) | 行为型 | 多租户差异化逻辑、支付路由 |
| 观察者模式(Observer) | 行为型 | 事件驱动架构、异步通知 |
| 工厂方法(Factory Method) | 创建型 | 多数据源适配、插件化扩展 |
| 代理模式(Proxy) | 结构型 | Feign 客户端、API Gateway、熔断 |
| 装饰器模式(Decorator) | 结构型 | 中间件链、日志增强、重试机制 |
下面逐一拆解。
一、策略模式(Strategy)
原理简述
策略模式将算法族封装成独立的类,使得它们可以互相替换。核心思想是"把变化的部分抽出来,让使用方不感知具体实现"。
UML 结构:
┌─────────────────┐
│ Context │
│ ┌─────────────┐ │
│ │ strategy │◄──────┐
│ └─────────────┘ │ │
│ execute() │ │
└─────────────────┘ │
│ implements
┌────────────────┼────────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ StrategyA │ │ StrategyB │ │ StrategyC │
│ execute() │ │ execute() │ │ execute() │
└──────────────┘ └──────────────┘ └──────────────┘
微服务场景:支付路由
在电商微服务中,支付服务需要根据不同条件(金额、地区、用户等级)选择不同的支付渠道。这是策略模式最典型的应用。
// 1. 定义策略接口
public interface PaymentStrategy {
/**
* 是否支持该支付条件
*/
boolean supports(PaymentContext context);
/**
* 执行支付
*/
PaymentResult pay(PaymentRequest request);
/**
* 优先级(数值越小优先级越高)
*/
int priority();
}
// 2. 具体策略实现
@Component
public class AlipayStrategy implements PaymentStrategy {
@Override
public boolean supports(PaymentContext context) {
return context.getRegion().equals("CN")
&& context.getAmount().compareTo(new BigDecimal("50000")) <= 0;
}
@Override
public PaymentResult pay(PaymentRequest request) {
// 调用支付宝 API
return alipayClient.tradePay(request);
}
@Override
public int priority() {
return 10;
}
}
@Component
public class WechatPayStrategy implements PaymentStrategy {
@Override
public boolean supports(PaymentContext context) {
return context.getRegion().equals("CN")
&& context.getChannel().equals("MOBILE");
}
@Override
public PaymentResult pay(PaymentRequest request) {
return wechatPayClient.unifiedOrder(request);
}
@Override
public int priority() {
return 20;
}
}
@Component
public class StripeStrategy implements PaymentStrategy {
@Override
public boolean supports(PaymentContext context) {
return !context.getRegion().equals("CN"); // 海外走 Stripe
}
@Override
public PaymentResult pay(PaymentRequest request) {
return stripeClient.charge(request);
}
@Override
public int priority() {
return 30;
}
}
// 3. 策略上下文(路由器)
@Service
public class PaymentRouter {
private final List<PaymentStrategy> strategies;
// Spring 自动注入所有 PaymentStrategy 实现
public PaymentRouter(List<PaymentStrategy> strategies) {
// 按优先级排序
this.strategies = strategies.stream()
.sorted(Comparator.comparingInt(PaymentStrategy::priority))
.collect(Collectors.toList());
}
public PaymentResult routeAndPay(PaymentContext context, PaymentRequest request) {
PaymentStrategy selected = strategies.stream()
.filter(s -> s.supports(context))
.findFirst()
.orElseThrow(() -> new UnsupportedPaymentException("无可用支付渠道"));
log.info("路由到支付策略: {}", selected.getClass().getSimpleName());
return selected.pay(request);
}
}
踩坑点
1. 策略选择不要硬编码 if-else:上面的实现通过 supports() + priority() 自动路由,新增支付渠道只需添加新的 @Component,符合开闭原则。
2. Spring 注入顺序问题:List 的注入顺序不确定,必须显式排序(用 @Order 或 priority() 方法)。
3. 策略状态管理:策略对象应该是无状态的(Stateless),如果涉及状态(如支付会话),使用 ThreadLocal 或外部存储。
二、观察者模式(Observer)
原理简述
观察者模式定义了对象间的一对多依赖关系。当一个对象状态改变时,所有依赖者都会收到通知。在微服务中,这就是事件驱动架构(EDA)的基础。
UML 结构:
┌──────────────┐ ┌──────────────────┐
│ Subject │────────▶│ Observer │
│ │ │ update(event) │
│ attach() │ └──────────────────┘
│ detach() │ ▲
│ notify() │ │
└──────────────┘ │ implements
│ ┌───────┴────────┐
│ ▼ ▼
│ ┌──────────────┐ ┌──────────────┐
└────▶│ ObserverA │ │ ObserverB │
│ update() │ │ update() │
└──────────────┘ └──────────────┘
微服务场景:领域事件发布
在订单微服务中,订单状态变更时需要通知多个下游服务(库存、物流、积分、通知)。使用 Spring 的 ApplicationEvent 实现进程内观察者:
// 1. 定义领域事件
public class OrderStatusChangedEvent extends ApplicationEvent {
private final String orderId;
private final OrderStatus oldStatus;
private final OrderStatus newStatus;
private final LocalDateTime occurredAt;
public OrderStatusChangedEvent(Object source, String orderId,
OrderStatus oldStatus, OrderStatus newStatus) {
super(source);
this.orderId = orderId;
this.oldStatus = oldStatus;
this.newStatus = newStatus;
this.occurredAt = LocalDateTime.now();
}
// getters...
}
// 2. 事件发布者(Subject)
@Service
public class OrderService {
@Autowired
private ApplicationEventPublisher eventPublisher;
@Autowired
private OrderRepository orderRepository;
@Transactional
public void confirmOrder(String orderId) {
Order order = orderRepository.findById(orderId)
.orElseThrow(() -> new OrderNotFoundException(orderId));
OrderStatus oldStatus = order.getStatus();
order.setStatus(OrderStatus.CONFIRMED);
orderRepository.save(order);
// 发布领域事件
eventPublisher.publishEvent(
new OrderStatusChangedEvent(this, orderId, oldStatus, OrderStatus.CONFIRMED)
);
}
}
// 3. 事件监听者(Observers)
@Component
public class InventoryObserver {
@Async
@EventListener
public void onOrderConfirmed(OrderStatusChangedEvent event) {
if (event.getNewStatus() == OrderStatus.CONFIRMED) {
log.info("库存扣减 - 订单: {}", event.getOrderId());
inventoryService.deductStock(event.getOrderId());
}
}
}
@Component
public class LogisticsObserver {
@Async
@EventListener
public void onOrderConfirmed(OrderStatusChangedEvent event) {
if (event.getNewStatus() == OrderStatus.CONFIRMED) {
log.info("物流创建 - 订单: {}", event.getOrderId());
logisticsService.createShipment(event.getOrderId());
}
}
}
@Component
public class NotificationObserver {
@Async
@EventListener
public void onOrderStatusChanged(OrderStatusChangedEvent event) {
notificationService.sendOrderUpdate(
event.getOrderId(),
event.getNewStatus()
);
}
}
跨服务的观察者:用 Kafka 实现
微服务之间的观察者模式通常借助消息队列实现:
// 发布者 - 订单服务
@Service
public class OrderEventPublisher {
@Autowired
private KafkaTemplate<String, String> kafkaTemplate;
@Autowired
private ObjectMapper objectMapper;
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void publishToKafka(OrderStatusChangedEvent event) {
try {
String payload = objectMapper.writeValueAsString(event);
kafkaTemplate.send("order-events", event.getOrderId(), payload);
log.info("订单事件已发布: orderId={}", event.getOrderId());
} catch (Exception e) {
log.error("事件发布失败: {}", e.getMessage());
// 记录到本地事件表,由定时任务补偿
outboxRepository.save(new OutboxEvent("order-events", event.getOrderId(), payload));
}
}
}
// 订阅者 - 库存服务
@Component
public class InventoryKafkaListener {
@KafkaListener(topics = "order-events", groupId = "inventory-service")
public void handleOrderEvent(String message) {
OrderStatusChangedEvent event = objectMapper.readValue(message,
OrderStatusChangedEvent.class);
if (event.getNewStatus() == OrderStatus.CONFIRMED) {
inventoryService.deductStock(event.getOrderId());
}
}
}
踩坑点
1. 事务一致性:事件发布必须在业务事务提交之后(@TransactionalEventListener(phase = AFTER_COMMIT)),否则观察者可能读到未提交的数据。
2. 幂等性:消息可能重复投递,所有观察者必须实现幂等处理。
3. 顺序问题:如果对事件顺序有要求(如先扣库存再创建物流),需要在消息 Key 中编码排序信息,或使用 Kafka 的 Partition 保序。
4. Outbox 模式:上面代码中的 Outbox 表是处理发布失败的关键——先把事件写入本地表,再由后台线程异步发送到 Kafka。
三、工厂方法(Factory Method)
原理简述
工厂方法定义一个创建对象的接口,但将实际创建推迟到子类。在微服务中,工厂方法常用于多数据源适配和多协议通信。
UML 结构:
┌────────────────────┐
│ AbstractFactory │
│ createProduct() │
└────────┬───────────┘
│ extends
┌────┴────┐
▼ ▼
┌────────┐ ┌────────┐ ┌──────────────┐
│ FactA │ │ FactB │──────▶│ Product │
│create()│ │create()│ uses │ operation() │
└────────┘ └────────┘ └──────────────┘
微服务场景:多数据源连接工厂
在企业级微服务中,一个服务可能需要连接多种数据库(MySQL、Redis、MongoDB、Elasticsearch),工厂方法可以统一管理连接创建:
// 1. 抽象工厂接口
public interface DataSourceFactory<T> {
/**
* 创建数据源连接
*/
T create(DataSourceConfig config);
/**
* 支持的数据源类型
*/
DataSourceType supportedType();
}
// 2. MySQL 数据源工厂
@Component
public class MySQLDataSourceFactory implements DataSourceFactory<DataSource> {
@Override
public DataSource create(DataSourceConfig config) {
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setJdbcUrl(config.getUrl());
hikariConfig.setUsername(config.getUsername());
hikariConfig.setPassword(config.getPassword());
hikariConfig.setMaximumPoolSize(config.getMaxPoolSize());
hikariConfig.setConnectionTimeout(config.getTimeoutMs());
return new HikariDataSource(hikariConfig);
}
@Override
public DataSourceType supportedType() {
return DataSourceType.MYSQL;
}
}
// 3. Redis 数据源工厂
@Component
public class RedisDataSourceFactory implements DataSourceFactory<RedisConnectionFactory> {
@Override
public RedisConnectionFactory create(DataSourceConfig config) {
RedisStandaloneConfiguration redisConfig = new RedisStandaloneConfiguration();
redisConfig.setHostName(config.getHost());
redisConfig.setPort(config.getPort());
redisConfig.setPassword(RedisPassword.of(config.getPassword()));
LettuceConnectionFactory factory = new LettuceConnectionFactory(redisConfig);
factory.afterPropertiesSet();
return factory;
}
@Override
public DataSourceType supportedType() {
return DataSourceType.REDIS;
}
}
// 4. 工厂注册中心
@Component
public class DataSourceFactoryRegistry {
private final Map<DataSourceType, DataSourceFactory<?>> factories;
public DataSourceFactoryRegistry(List<DataSourceFactory<?>> factoryList) {
this.factories = factoryList.stream()
.collect(Collectors.toMap(
DataSourceFactory::supportedType,
Function.identity()
));
}
@SuppressWarnings("unchecked")
public <T> DataSourceFactory<T> getFactory(DataSourceType type) {
DataSourceFactory<?> factory = factories.get(type);
if (factory == null) {
throw new UnsupportedDataSourceException("不支持的数据源类型: " + type);
}
return (DataSourceFactory<T>) factory;
}
}
// 5. 使用示例
@Service
public class MultiDataSourceManager {
@Autowired
private DataSourceFactoryRegistry registry;
private final Map<String, Object> activeConnections = new ConcurrentHashMap<>();
public void initDataSource(String name, DataSourceConfig config) {
DataSourceFactory<?> factory = registry.getFactory(config.getType());
Object connection = factory.create(config);
activeConnections.put(name, connection);
log.info("数据源 {} ({}) 初始化完成", name, config.getType());
}
}
踩坑点
1. 工厂注册时机:Spring 容器启动时工厂列表可能不完整(特别是涉及 SPI 加载的),建议使用 @DependsOn 或 SmartInitializingSingleton 确保注册完成。
2. 连接生命周期:工厂创建的对象(如 DataSource)需要管理生命周期,实现 DisposableBean 或在 @PreDestroy 中释放资源。
3. 配置热更新:如果数据源配置需要热更新,工厂应支持重新创建连接并替换旧连接(注意优雅关闭)。
四、代理模式(Proxy)
原理简述
代理模式为另一个对象提供一个替身以控制对其的访问。在微服务中,代理模式无处不在:Feign 客户端是远程代理,Spring AOP 是动态代理,API Gateway 是反向代理。
UML 结构:
┌─────────────┐ ┌──────────────────────┐
│ Client │──────▶│ Subject │
└─────────────┘ │ request() │
└──────────┬───────────┘
│
┌────────────┴────────────┐
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Proxy │────────▶│ RealSubject │
│ request() │ calls │ request() │
│ (增强逻辑) │ │ (真实逻辑) │
└──────────────┘ └──────────────┘
微服务场景:自定义 Feign 拦截代理
Spring Cloud OpenFeign 本身就是代理模式的典型实现。在此基础上,我们可以添加自定义代理逻辑(如请求签名、流量染色):
// 1. 定义 Feign 客户端接口
@FeignClient(name = "user-service", configuration = FeignProxyConfig.class)
public interface UserServiceClient {
@GetMapping("/api/users/{id}")
UserDTO getUser(@PathVariable("id") Long userId);
@PostMapping("/api/users/batch")
List<UserDTO> batchGetUsers(@RequestBody List<Long> userIds);
}
// 2. Feign 配置 - 添加代理拦截器
public class FeignProxyConfig {
@Bean
public RequestInterceptor tracingInterceptor() {
return template -> {
// 传播 TraceId
String traceId = MDC.get("traceId");
if (traceId != null) {
template.header("X-Trace-Id", traceId);
}
// 传播用户上下文
UserContext ctx = UserContextHolder.get();
if (ctx != null) {
template.header("X-User-Id", ctx.getUserId().toString());
template.header("X-Tenant-Id", ctx.getTenantId());
}
// 流量染色(灰度发布)
String trafficTag = TrafficRouter.getCurrentTag();
if (trafficTag != null) {
template.header("X-Traffic-Tag", trafficTag);
}
// 请求签名
String signature = SignatureUtil.sign(template.url(), template.queries());
template.header("X-Signature", signature);
};
}
@Bean
public Retryer feignRetryer() {
// 重试策略:初始间隔100ms,最大间隔1s,最多重试3次
return new Retryer.Default(100, 1000, 3);
}
@Bean
public ErrorDecoder errorDecoder() {
return (methodKey, response) -> {
int status = response.status();
if (status == 429) {
throw new RetryableException(
response.status(), "限流,稍后重试",
response.request().httpMethod(), null, response.request());
}
if (status >= 500) {
throw new RetryableException(
response.status(), "服务端错误",
response.request().httpMethod(), null, response.request());
}
return new FeignClientException(status, "Feign调用失败: " + methodKey);
};
}
}
// 3. 更高级的动态代理 - 带熔断的包装
@Component
public class CircuitBreakerProxy<T> {
private final CircuitBreakerRegistry registry;
public CircuitBreakerProxy(CircuitBreakerRegistry registry) {
this.registry = registry;
}
@SuppressWarnings("unchecked")
public T wrap(T target, Class<T> interfaceType, String serviceName) {
CircuitBreaker cb = registry.circuitBreaker(serviceName);
return (T) Proxy.newProxyInstance(
interfaceType.getClassLoader(),
new Class<?>[]{interfaceType},
(proxy, method, args) -> {
return cb.executeSupplier(() -> {
try {
return method.invoke(target, args);
} catch (InvocationTargetException e) {
throw new RuntimeException(e.getCause());
}
});
}
);
}
}
// 4. 使用带熔断的代理
@Configuration
public class FeignClientWrapper {
@Bean
public UserServiceClient userServiceClient(
CircuitBreakerProxy<UserServiceClient> proxy,
UserServiceClient rawClient) {
return proxy.wrap(rawClient, UserServiceClient.class, "user-service");
}
}
踩坑点
1. 代理层级过深:如果同时使用 Feign + Hystrix/Resilience4j + Spring AOP + 自定义代理,方法调用链会非常长,排查问题时注意 stacktrace 中的实际目标方法。
2. 泛型擦除:JDK 动态代理在处理泛型返回类型时可能丢失类型信息,建议使用 ParameterizedTypeReference 或显式类型转换。
3. 性能开销:每增加一层代理,调用开销增加约 0.1-0.5ms。在高 QPS 场景下需要评估代理层数。
五、装饰器模式(Decorator)
原理简述
装饰器模式动态地给对象添加额外职责,比继承更灵活。在微服务中,装饰器模式的典型应用是中间件链(Middleware Chain)和请求增强。
UML 结构:
┌───────────────────┐
│ Component │
│ operation() │
└────────┬──────────┘
│
┌────┴─────────────────┐
▼ ▼
┌──────────┐ ┌──────────────────┐
│Concrete │ │ Decorator │
│Component │ │ ┌────────────┐ │
│operation │ │ │ component │ │
└──────────┘ │ └────────────┘ │
│ operation() { │
│ // 增强逻辑 │
│ component.op() │
│ } │
└────────┬─────────┘
│ extends
┌─────┴──────┐
▼ ▼
┌──────────┐ ┌──────────┐
│ DecorA │ │ DecorB │
│(日志) │ │(限流) │
└──────────┘ └──────────┘
微服务场景:HTTP 客户端装饰器链
在调用外部服务时,通常需要叠加多种横切关注点(日志、重试、限流、缓存)。装饰器模式让这些关注点可以灵活组合:
// 1. 基础接口
public interface HttpClient {
HttpResponse execute(HttpRequest request) throws Exception;
}
// 2. 基础实现(委托给 RestTemplate)
public class RestTemplateHttpClient implements HttpClient {
private final RestTemplate restTemplate;
public RestTemplateHttpClient(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
@Override
public HttpResponse execute(HttpRequest request) {
ResponseEntity<String> response = restTemplate.exchange(
request.getUrl(),
HttpMethod.valueOf(request.getMethod()),
new HttpEntity<>(request.getBody(), request.getHeaders()),
String.class
);
return new HttpResponse(response.getStatusCodeValue(), response.getBody());
}
}
// 3. 日志装饰器
public class LoggingDecorator implements HttpClient {
private final HttpClient delegate;
public LoggingDecorator(HttpClient delegate) {
this.delegate = delegate;
}
@Override
public HttpResponse execute(HttpRequest request) throws Exception {
long start = System.currentTimeMillis();
log.info("→ {} {}", request.getMethod(), request.getUrl());
try {
HttpResponse response = delegate.execute(request);
long elapsed = System.currentTimeMillis() - start;
log.info("← {} {}ms status={}", request.getUrl(), elapsed, response.getStatus());
return response;
} catch (Exception e) {
long elapsed = System.currentTimeMillis() - start;
log.error("✗ {} {}ms error={}", request.getUrl(), elapsed, e.getMessage());
throw e;
}
}
}
// 4. 重试装饰器
public class RetryDecorator implements HttpClient {
private final HttpClient delegate;
private final int maxRetries;
private final long retryDelayMs;
public RetryDecorator(HttpClient delegate, int maxRetries, long retryDelayMs) {
this.delegate = delegate;
this.maxRetries = maxRetries;
this.retryDelayMs = retryDelayMs;
}
@Override
public HttpResponse execute(HttpRequest request) throws Exception {
Exception lastException = null;
for (int attempt = 0; attempt <= maxRetries; attempt++) {
try {
return delegate.execute(request);
} catch (Exception e) {
lastException = e;
if (attempt < maxRetries) {
log.warn("重试 {}/{}: {} - {}", attempt + 1, maxRetries,
request.getUrl(), e.getMessage());
Thread.sleep(retryDelayMs * (attempt + 1)); // 指数退避
}
}
}
throw lastException;
}
}
// 5. 限流装饰器
public class RateLimitDecorator implements HttpClient {
private final HttpClient delegate;
private final RateLimiter rateLimiter;
public RateLimitDecorator(HttpClient delegate, double permitsPerSecond) {
this.delegate = delegate;
this.rateLimiter = RateLimiter.create(permitsPerSecond);
}
@Override
public HttpResponse execute(HttpRequest request) throws Exception {
if (!rateLimiter.tryAcquire(1, 500, TimeUnit.MILLISECONDS)) {
throw new RateLimitExceededException("请求限流: " + request.getUrl());
}
return delegate.execute(request);
}
}
// 6. 组装装饰器链
@Configuration
public class HttpClientConfig {
@Bean
public HttpClient httpClient(RestTemplate restTemplate) {
HttpClient base = new RestTemplateHttpClient(restTemplate);
// 装饰器链:限流 → 重试 → 日志 → 基础实现
// 执行顺序:日志(最先执行) → 重试 → 限流 → 真实调用
return new LoggingDecorator(
new RetryDecorator(
new RateLimitDecorator(base, 100.0), // 100 QPS
3, // 最多重试 3 次
500 // 初始重试间隔 500ms
)
);
}
}
进阶:Spring 的 HandlerInterceptor 也是装饰器
Spring MVC 的拦截器链本质上就是装饰器模式的应用:
// 请求处理链:
// PreHandle(Auth) → PreHandle(Log) → Controller → PostHandle(Log) → PostHandle(Auth)
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) {
String token = request.getHeader("Authorization");
if (!jwtService.validate(token)) {
response.setStatus(401);
return false; // 终止链
}
return true; // 继续下一个装饰器
}
}
public class RequestLoggingInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) {
MDC.put("traceId", UUID.randomUUID().toString());
request.setAttribute("startTime", System.currentTimeMillis());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) {
long elapsed = System.currentTimeMillis() - (Long) request.getAttribute("startTime");
log.info("{} {} {}ms", request.getMethod(), request.getRequestURI(), elapsed);
MDC.clear();
}
}
踩坑点
1. 装饰器顺序很重要:限流应该在重试之前还是之后?如果限流在重试之后,重试请求不会被限流,可能压垮下游。正确顺序:日志 → 限流 → 重试 → 真实调用。
2. 异常透传:装饰器中的异常处理要谨慎,不要让装饰器吞掉原始异常,否则排查问题很困难。
3. 组合爆炸:装饰器数量不宜过多(建议 3-5 层),否则调试复杂度指数增长。超过这个数量时考虑用 AOP 或 Pipeline 模式替代。
5 个模式的协作关系
在实际微服务项目中,这 5 个模式往往不是独立使用的,而是相互配合:
典型请求处理流程中的模式应用:
[客户端请求]
│
▼
┌─────────────────────────────────────────┐
│ API Gateway │
│ ┌─────────────────────────────────┐ │
│ │ 装饰器链: 限流→鉴权→日志 │ │ ← 装饰器模式
│ └─────────────────────────────────┘ │
└──────────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ 业务服务 │
│ ┌──────────────┐ ┌──────────────────┐ │
│ │ 工厂创建 │ │ 策略选择 │ │ ← 工厂+策略
│ │ 数据源连接 │ │ 业务处理逻辑 │ │
│ └──────────────┘ └──────────────────┘ │
│ │
│ ┌──────────────────────────────────┐ │
│ │ 代理调用下游服务(Feign+熔断) │ │ ← 代理模式
│ └──────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────┐ │
│ │ 发布领域事件 │ │ ← 观察者模式
│ │ → Kafka → 下游服务订阅 │ │
│ └──────────────────────────────────┘ │
└─────────────────────────────────────────┘
设计模式不是教条,而是经验的沉淀。在微服务架构中,理解这些模式的核心意图比记住 UML 图更重要。当你在代码中看到 if-else 越来越多时,想想策略模式;当你在服务间传递状态时,想想观察者模式;当你需要灵活组合行为时,想想装饰器模式。
原文链接:https://wenyiblog.top/2026/06/five-design-patterns-microservices/
首发于文艺技术笔记(wenyiblog.top),转载请注明出处。

浙公网安备 33010602011771号