说一下你在实际项目开发中都用到了哪些设计模式
重点展开 3~5 个
1. 策略模式 + 工厂模式
场景:
我在银行信用卡中心中还款的时候,对接了多家支付渠道,这个时候就使用到了策略模式+工厂模式。
做法:
public interface PayStrategy {
PayResult pay(PayRequest request);
String getPayType();
}
每个渠道一个实现类,交给 Spring 管理。再用一个工厂或路由:
@Component
public class PayStrategyFactory {
private final Map<String, PayStrategy> strategyMap;
public PayStrategyFactory(List<PayStrategy> strategies) {
strategyMap = strategies.stream()
.collect(Collectors.toMap(PayStrategy::getPayType, s -> s));
}
public PayStrategy get(String payType) {
PayStrategy strategy = strategyMap.get(payType);
if (strategy == null) throw new BizException("不支持的支付方式");
return strategy;
}
}
2. 责任链模式:风控、审批、参数校验
场景:
我在做信用卡还款的时候,Java后端校验逻辑:
1、借记卡持卡人姓名、证件类型、证件号码、手机号,必须与信用卡账户登记信息完全一致。不一致直接拦截。借记卡持卡人姓名、证件类型、证件号码、手机号,必须与信用卡账户登记信息完全一致。不一致直接拦截。
2、账户状态校验:是否冻结、挂失、注销等等。
3、借记卡的金额是否充足。
4、借记卡限额校验。
5、还款笔数校验。
6、黑灰名单校验。
等等。
做法:
public interface OrderCheckHandler {
void check(OrderContext context);
int order();
}
每个校验器实现接口,Spring 注入 List<OrderCheckHandler>,按 order() 排序后依次执行。也可以手动维护 next 指针。
3. 模板方法模式:数据同步 / 导入导出
场景:
在银行的时候,做数据入湖入仓的时候,要将表中的数据导出到文件中,因为每张表的数据都不一样,倒是最终结果都是导出到文件中,这个时候我们使用到了模板方法模式。
做法:
public abstract class AbstractSyncTask {
public final void execute() {
List<RawData> raw = fetch();
List<BizData> data = convert(raw);
validate(data);
save(data);
recordLog();
}
protected abstract List<RawData> fetch();
protected abstract List<BizData> convert(List<RawData> raw);
// 通用方法直接实现
}
4. 观察者模式:订单状态变更后的通知
场景:
我在做4A权限管理平台项目的时候,用户变更权限,这个时候我们会变更信息封装为事件,然后发送到缓存(R2M)中,使用的是spring框架的事件发送机制,这其实就是观察者模式的一种应用。
做法:
用 Spring 的 ApplicationEvent:
publisher.publishEvent(new OrderPaidEvent(orderId));
各监听器处理自己的逻辑:
@EventListener
public void addPoints(OrderPaidEvent event) { ... }
@TransactionalEventListener(phase = AFTER_COMMIT)
public void sendMq(OrderPaidEvent event) { ... }
效果: 支付主流程只关注支付,后续动作解耦。
注意: 默认同步,耗时长可加 @Async;涉及事务要用 @TransactionalEventListener;分布式场景用 MQ。
5. 代理模式:AOP 日志、事务、权限
场景:
接口日志、耗时统计、事务、权限校验,如果每个方法手写,重复代码太多。
做法:
Spring AOP 底层就是动态代理:接口用 JDK 动态代理,类用 CGLIB。自定义注解 + 切面:
@Around("@annotation(com.xxx.Log)")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
try {
return pjp.proceed();
} finally {
log.info("cost={}", System.currentTimeMillis() - start);
}
}
浙公网安备 33010602011771号