设计模式:完结-->设计模式常见问题解答总结

面向资深Java工程师的设计模式深度解析与实践

前言

作为阿里/字节跳动等大厂资深Java工程师,设计模式不仅是面试高频考点,更是日常开发中解决复杂问题的利器。本文将深入剖析几种关键设计模式,结合分布式系统实战经验,提供可直接复用的代码示例,并针对大厂面试常见深度追问给出系统化解决方案。

一、责任链模式在风控系统中的应用

1.1 模式定义与UML

责任链模式(Chain of Responsibility)使多个对象都有机会处理请求,从而避免请求发送者与接收者耦合。

«abstract»
Handler
+successor: Handler
+handleRequest(Request)
+setSuccessor(Handler)
ConcreteHandlerA
+handleRequest(Request)
ConcreteHandlerB
+handleRequest(Request)

1.2 系统流程图

风险请求
账号风控检查
通过?
拒绝
设备风控检查
通过?
行为风控检查
通过?
通过

1.3 代码实现示例

public interface RiskHandler {
    void handle(RiskRequest request, RiskResponse response);
    void setNext(RiskHandler handler);
}

public abstract class AbstractRiskHandler implements RiskHandler {
    private RiskHandler next;
    
    @Override
    public void setNext(RiskHandler handler) {
        this.next = handler;
    }
    
    protected void doNext(RiskRequest request, RiskResponse response) {
        if (next != null && !response.isBlocked()) {
            next.handle(request, response);
        }
    }
}

public class AccountRiskHandler extends AbstractRiskHandler {
    @Override
    public void handle(RiskRequest request, RiskResponse response) {
        if (request.getAccount().isBlacklisted()) {
            response.block("账号黑名单");
        }
        doNext(request, response);
    }
}

// 客户端使用
RiskHandler chain = new AccountRiskHandler()
    .setNext(new DeviceRiskHandler())
    .setNext(new BehaviorRiskHandler());
chain.handle(request, response);

1.4 应用场景与优缺点

适用场景

  • 风控系统多规则校验
  • 审批流程(如报销审批)
  • 过滤器链(如Servlet Filter)

优点

  • 解耦请求发送者和接收者
  • 动态调整处理链顺序
  • 符合开闭原则

缺点

  • 请求可能未被处理
  • 调试复杂度较高

1.5 大厂面试深度追问

问题:在分布式环境下如何实现高性能的责任链模式?如何保证处理链的原子性?

解决方案

在分布式系统中实现责任链需要考虑以下关键点:

  1. 异步化处理:将同步责任链改为异步流水线
// 使用CompletableFuture实现异步链
CompletableFuture<RiskResult> future = CompletableFuture
    .supplyAsync(() -> accountCheck(request), executor)
    .thenCombineAsync(deviceCheck(request), this::mergeResult, executor)
    .thenCombineAsync(behaviorCheck(request), this::mergeResult, executor);
  1. 规则引擎优化
  • 将规则按优先级排序,短路执行(如第一个拒绝规则命中即终止)
  • 使用规则决策表实现快速匹配
  1. 原子性保证
Client LockService HandlerChain 获取分布式锁(key=requestId) 获取成功 执行处理链 返回结果 释放锁 Client LockService HandlerChain
  1. 性能优化方案
  • 并行执行无依赖的检查项
List<CompletableFuture<CheckResult>> futures = Arrays.asList(
    CompletableFuture.supplyAsync(() -> rule1.check(request)),
    CompletableFuture.supplyAsync(() -> rule2.check(request))
);
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
  • 实现规则缓存(如使用Caffeine缓存近期通过的规则结果)
  • 分级处理(先执行轻量级规则,再执行重量级规则)
  1. 容错机制
  • 为每个处理器设置超时时间
  • 实现熔断机制(如某个规则连续失败N次则临时跳过)
  • 提供降级策略(如部分规则超时后按默认结果处理)

二、策略模式在支付路由系统中的应用

2.1 模式定义与UML

策略模式(Strategy)定义一系列算法,封装每个算法,并使它们可以互换。

Context
-strategy: Strategy
+executeStrategy()
«interface»
Strategy
+execute()
ConcreteStrategyA
+execute()
ConcreteStrategyB
+execute()

2.2 支付路由时序图

Client PaymentService StrategyManager BankAStrategy BankBStrategy 支付请求(amount=5000) 获取最优策略 计算手续费 返回30 计算手续费 返回25 选择BankB 执行支付 支付成功 返回结果 Client PaymentService StrategyManager BankAStrategy BankBStrategy

2.3 代码实现示例

public interface PaymentStrategy {
    PaymentResult execute(PaymentRequest request);
    BigDecimal calculateFee(PaymentRequest request);
}

public class BankAStrategy implements PaymentStrategy {
    @Override
    public PaymentResult execute(PaymentRequest request) {
        // 调用银行A的API
    }
    
    @Override
    public BigDecimal calculateFee(PaymentRequest request) {
        return request.getAmount().multiply(new BigDecimal("0.006"));
    }
}

public class PaymentRouter {
    private Map<String, PaymentStrategy> strategies;
    
    public PaymentResult route(PaymentRequest request) {
        PaymentStrategy strategy = selectBestStrategy(request);
        return strategy.execute(request);
    }
    
    private PaymentStrategy selectBestStrategy(PaymentRequest request) {
        return strategies.values().stream()
            .min(Comparator.comparing(s -> s.calculateFee(request)))
            .orElseThrow(() -> new RuntimeException("No available strategy"));
    }
}

2.4 大厂面试深度追问

问题:如何实现支付策略的动态热更新?如何保证策略切换时的数据一致性?

解决方案

  1. 动态策略加载架构
发布更新
通知变更
验证通过
策略管理后台
配置中心
支付服务
重新加载策略
验证新策略
切换策略
  1. 热更新实现要点
// 使用AtomicReference保证原子性切换
public class StrategyManager {
    private AtomicReference<Map<String, PaymentStrategy>> strategiesRef;
    
    @Scheduled(fixedRate = 5000)
    public void refreshStrategies() {
        Map<String, PaymentStrategy> newStrategies = loadStrategiesFromDB();
        strategiesRef.set(newStrategies);
    }
    
    public PaymentStrategy getStrategy(String key) {
        return strategiesRef.get().get(key);
    }
}
  1. 数据一致性保障措施
  • 双写期间的事务处理:
@Transactional
public void switchStrategy(String newStrategy) {
    // 1. 将进行中的交易使用旧策略完成
    List<Transaction> pending = transactionRepo.findPending();
    completeWithOldStrategy(pending);
    
    // 2. 原子性切换策略版本
    versionControl.compareAndSet(currentVersion, newVersion);
    
    // 3. 新交易使用新策略
    enableNewStrategy();
}
  • 采用版本号控制,每次策略更新递增版本
  • 实现灰度发布机制,逐步切流验证
  1. 异常处理方案
  • 策略回滚机制(当新策略失败率超过阈值时自动回退)
  • 设置策略熔断器(如Circuit Breaker模式)
  • 保留旧策略的兼容处理
  1. 性能优化方向
  • 策略缓存预热
  • 策略索引优化(使用决策树组织策略)
  • 并行策略评估(对无状态策略可并行计算)

三、观察者模式在订单状态通知系统中的应用

3.1 模式定义与UML

观察者模式(Observer)定义对象间的一对多依赖关系,当一个对象状态改变时,所有依赖它的对象都得到通知。

«interface»
Subject
+registerObserver(Observer)
+removeObserver(Observer)
+notifyObservers()
ConcreteSubject
-state: Object
+getState()
+setState(Object)
«interface»
Observer
+update()
ConcreteObserverA
+update()
ConcreteObserverB
+update()

3.2 订单通知时序图

OrderService NotificationSystem AnalyticsSystem WarehouseSystem 订单状态变更为"已支付" notifyObservers() 处理通知逻辑 更新分析数据 触发备货 ACK ACK OrderService NotificationSystem AnalyticsSystem WarehouseSystem

3.3 代码实现示例

public interface OrderObserver {
    void onOrderStateChanged(Order order, OrderState previousState);
}

// 使用Spring事件机制实现
public class OrderStateChangeEvent extends ApplicationEvent {
    private final Order order;
    private final OrderState previousState;
    
    public OrderStateChangeEvent(Object source, Order order, OrderState previousState) {
        super(source);
        this.order = order;
        this.previousState = previousState;
    }
    // getters
}

@Service
public class OrderService {
    @Autowired
    private ApplicationEventPublisher eventPublisher;
    
    public void updateOrderState(Long orderId, OrderState newState) {
        Order order = getOrder(orderId);
        OrderState previousState = order.getState();
        order.setState(newState);
        saveOrder(order);
        
        eventPublisher.publishEvent(
            new OrderStateChangeEvent(this, order, previousState));
    }
}

@Component
public class WarehouseNotifier {
    @EventListener
    @Async
    public void handleOrderPaid(OrderStateChangeEvent event) {
        if (event.getOrder().getState() == OrderState.PAID) {
            // 调用WMS系统接口
        }
    }
}

3.4 大厂面试深度追问

问题:在大规模订单系统中,如何保证观察者通知的可靠性和顺序性?当观察者处理失败时如何设计重试机制?

解决方案

  1. 可靠性架构设计
失败
订单状态变更
持久化事件到DB
写入消息队列
消费者处理
成功则ACK
进入死信队列
人工干预/自动重试
  1. 顺序性保障方案
  • 采用分区有序消息(如Kafka的partition key使用订单ID)
// 确保同一订单的事件进入同一分区
kafkaTemplate.send("order-events", orderId.toString(), eventJson);
  • 在消费者端实现状态机校验
  • 使用版本号或时间戳进行顺序检测
  1. 重试机制设计
@Retryable(value = {RuntimeException.class}, 
           maxAttempts = 3,
           backoff = @Backoff(delay = 1000, multiplier = 2))
public void processOrderEvent(OrderEvent event) {
    // 处理逻辑
}

// 最终失败后进入死信队列处理
@Recover
public void recover(RuntimeException e, OrderEvent event) {
    deadLetterQueue.push(event, e.getMessage());
}
  1. 分布式事务方案
  • 本地消息表模式:
BEGIN TRANSACTION;
UPDATE orders SET state = 'PAID' WHERE id = 1001;
INSERT INTO event_log (event_id, event_type, payload, status) 
VALUES ('evt_123', 'ORDER_PAID', '{"orderId":1001}', 'PENDING');
COMMIT;
  • 定时任务扫描event_log表进行补偿
  1. 性能优化措施
  • 观察者异步化处理(线程池隔离)
  • 批量事件处理(如积攒100ms内的订单事件批量处理)
  • 关键观察者优先处理(如支付成功通知优先于数据分析)

四、工厂方法模式在跨云存储适配中的应用

4.1 模式定义与UML

工厂方法模式(Factory Method)定义一个创建对象的接口,但让子类决定实例化哪个类。

«abstract»
Creator
+factoryMethod()
+operation()
ConcreteCreatorA
+factoryMethod()
ConcreteCreatorB
+factoryMethod()
«interface»
Product
+doStuff()
ConcreteProductA
+doStuff()
ConcreteProductB
+doStuff()

4.2 云存储选择流程图

图片
视频
文档
上传请求
文件类型?
选择OSS存储
选择视频云存储
选择文档存储
执行上传

4.3 代码实现示例

public interface CloudStorage {
    String upload(File file);
    InputStream download(String key);
}

public interface StorageFactory {
    CloudStorage createStorage(StorageConfig config);
}

public class OssFactory implements StorageFactory {
    @Override
    public CloudStorage createStorage(StorageConfig config) {
        return new OssStorage(config.getEndpoint(), 
                            config.getAccessKey(),
                            config.getSecretKey());
    }
}

public class StorageClient {
    private final Map<StorageType, StorageFactory> factories;
    
    public CloudStorage getStorage(StorageType type) {
        StorageFactory factory = factories.get(type);
        if (factory == null) {
            throw new IllegalArgumentException("Unsupported storage type");
        }
        return factory.createStorage(getConfig(type));
    }
    
    // 动态注册工厂
    public void registerFactory(StorageType type, StorageFactory factory) {
        factories.put(type, factory);
    }
}

// 使用示例
StorageClient client = new StorageClient();
client.registerFactory(StorageType.OSS, new OssFactory());
client.registerFactory(StorageType.S3, new S3Factory());

CloudStorage storage = client.getStorage(StorageType.OSS);
String url = storage.upload(file);

4.4 大厂面试深度追问

问题:如何设计支持动态注册存储厂商的工厂模式?在多租户场景下如何实现存储隔离?

解决方案

  1. 动态注册架构设计
RegisterCenter StorageFactory StorageClient 注册工厂(type=OSS, version=1.0) 查询可用工厂(type=OSS) 返回工厂列表 创建存储实例 返回存储对象 RegisterCenter StorageFactory StorageClient
  1. 多租户隔离方案
  • 租户上下文传递:
public class TenantContext {
    private static final ThreadLocal<String> currentTenant = new ThreadLocal<>();
    
    public static void setTenant(String tenant) {
        currentTenant.set(tenant);
    }
    
    public static String getTenant() {
        return currentTenant.get();
    }
}

// 在工厂中应用租户隔离
public class TenantAwareOssStorage implements CloudStorage {
    private String getTenantBucket() {
        return TenantContext.getTenant() + "-bucket";
    }
    
    @Override
    public String upload(File file) {
        String bucket = getTenantBucket();
        // 上传到租户特定bucket
    }
}
  1. 动态类加载机制
public class DynamicStorageFactory implements StorageFactory {
    private final String className;
    private final ClassLoader classLoader;
    
    public DynamicStorageFactory(String className, ClassLoader classLoader) {
        this.className = className;
        this.classLoader = classLoader;
    }
    
    @Override
    public CloudStorage createStorage(StorageConfig config) {
        try {
            Class<?> clazz = classLoader.loadClass(className);
            Constructor<?> ctor = clazz.getConstructor(StorageConfig.class);
            return (CloudStorage) ctor.newInstance(config);
        } catch (Exception e) {
            throw new RuntimeException("Failed to create storage", e);
        }
    }
}
  1. 存储策略路由
public class SmartStorageRouter {
    private List<StorageFactory> factories;
    
    public CloudStorage route(File file, User user) {
        // 根据文件类型、大小、用户等级等选择最优存储
        StorageFactory factory = factories.stream()
            .filter(f -> f.supports(file, user))
            .max(Comparator.comparingInt(f -> f.getPriority(file, user)))
            .orElseThrow();
        
        return factory.createStorage(getConfig(user));
    }
}
  1. 安全隔离措施
  • 每个租户独立的访问凭证
  • 存储路径包含租户前缀
  • 网络隔离(VPC内访问)
  • 加密存储(租户级加密密钥)

结语

设计模式的深度理解需要结合实际系统架构,本文展示的四种模式在分布式系统中都有广泛应用。大厂面试不仅考察模式本身,更关注在复杂场景下的灵活运用和问题解决能力。建议读者:

  1. 对每个模式至少准备2个真实应用案例
  2. 掌握模式组合使用的技巧(如策略+工厂)
  3. 理解模式在分布式环境下的变体实现
  4. 准备性能优化和异常处理的方案

希望本文能为您的技术成长和面试准备提供实质性帮助。在阿里/字节等大厂面试中,能够结合真实场景深入分析设计模式,往往能获得面试官的高度认可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值