🌟 告别支付系统"屎山"!我用3种设计模式写出优雅如诗的后台

72 阅读8分钟

🌟 告别支付系统"屎山"!我用3种设计模式写出优雅如诗的后台

面试官:如果让你设计一个支持 微信支付、支付宝、快捷支付、余额支付,并且要处理 会员开通、物流邮费、余额充值 等多种业务场景的支付系统,你会怎么设计?

🎯 从“面试噩梦”到“设计艺术品”

支付模块——这个让无数后端开发者又爱又恨的“业务核心区”。爱的是它的重要性,恨的是它那令人窒息的复杂度:

  • 每加一个支付方式,代码就膨胀一圈
  • 每新增一个业务场景,if-else就多一层
  • 每改动一处逻辑,就害怕牵一发而动全身
  • 看着日渐臃肿的PaymentService,内心OS:这真的不是“屎山”吗?

今天,我要分享的不是又一个平庸的解决方案,而是一个融合了模板方法、策略模式、工厂模式三位一体的优雅设计。它让支付系统的扩展变得像搭积木一样简单,维护起来如同阅读优美的诗篇。

🔥 第一幕:传统设计的“悲剧”

先看看我们想避免的“反面教材”:


// ❌ 传说中的“万能支付类”(5000+行代码预警)
public class PaymentService {
    
    public PayResult pay(String payType, String bizType, Object param) {
        if ("WECHAT".equals(payType)) {
            if ("MEMBER".equals(bizType)) {
                // 微信会员支付逻辑(300行)
            } else if ("SHIPPING".equals(bizType)) {
                // 微信物流支付逻辑(300行)
            } // ... 还有10个else if
        } else if ("ALIPAY".equals(payType)) {
            // 再来一套类似的嵌套地狱
        } else if ("BALANCE".equals(payType)) {
            // 再来一套...
        }
        // 方法继续膨胀到1000行...
    }
}

这种代码的“七宗罪”:

  1. 改一处而动全身:修微信支付可能影响支付宝
  2. 新人不敢碰:几千行的类谁看谁头疼
  3. 测试噩梦:分支路径多到测不完
  4. 扩展成本高:新增支付方式要改N个地方

✨ 第二幕:我们的“优雅革命”

🎩 设计思路:像点餐一样设计支付系统

想象一下你去餐厅吃饭:

  1. 服务员(工厂)  问:您要什么菜系?(支付方式)
  2. 您选择:川菜(微信支付)、粤菜(支付宝)、家常菜(余额支付)
  3. 厨师(模板)  按固定流程:备菜→烹饪→装盘
  4. 具体菜品(策略) :宫保鸡丁、水煮鱼...

我们的设计正是如此:


🛠️ 三大模式,各司其职:

🔸 模板方法模式 → 固定“烹饪流程”
   所有支付必须走:校验→创建订单→调用通道→处理结果
    
🔸 策略模式 → 定义“不同菜系的做法”
   微信支付、支付宝、余额支付...每个都有自己的实现
    
🔸 工厂模式 → 智能“服务员”
   “客人要微信支付?好的,马上安排微信支付策略”

💻 第三幕:代码里的“优雅舞蹈”

🌈 核心骨架:支付流程的“宪法”


// 🎯 AbstractTradePayment.java - 支付界的“宪法”
public abstract class AbstractTradePayment {
    
    // 📜 这是所有支付必须遵守的“基本法”
    public final BasePayResult processPay(BasePayParam order) {
        // 第1步:基础校验(身份证检查)
        this.baseParamCheck(order);
        
        // 第2步:业务校验(钱包余额够吗?)
        this.businessParamValid(order);
        
        // 第3步:留痕(创建交易记录)
        TraderOrder traderOrder = this.createTradeOrder(order);
        
        // 第4步:执行(真正付钱)
        BasePayResult result = this.requestBankChannel(traderOrder);
        
        // 第5步:善后(更新状态,通知业务)
        tradeOrderCompleteManage.completePayTrade(result, traderOrder);
        
        return result;
    }
    
    // ⚡️ 这三个方法由“各省市自治区”自行决定
    protected abstract void businessParamValid(BasePayParam order);
    protected abstract BasePayResult requestBankChannel(TraderOrder order);
    public abstract boolean isSupport(String payWay);
}

设计哲学:把不变的固化(宪法),把变化的抽象(地方性法规)。

🎨 具体实现:每个支付方式的“个性”


// 💚 微信支付 - 像小程序一样轻巧
@Service
public class WechatPayWayProcess extends AbstractTradePayment {
    
    @Override
    protected BasePayResult requestBankChannel(TraderOrder order) {
        // 🎪 这里是微信支付的“魔法舞台”
        WechatPayResult result = new WechatPayResult();
        result.setPayMessage("生成小程序支付参数...");
        result.setTradeStatus(TradeStatusEnum.PAYING);
        return result;
    }
    
    @Override
    public boolean isSupport(String payWay) {
        // 🎯 精准识别:“我是微信支付专家”
        return PayWay.WECHAT.name().equals(payWay);
    }
}

// 💳 余额支付 - 像钱包一样直接
@Service  
public class BalancePayWayProcess extends AbstractTradePayment {
    
    @Override
    protected BasePayResult requestBankChannel(TraderOrder order) {
        // 💰 扣余额,就是这么直接
        BalancePayResult result = new BalancePayResult();
        result.setBalance(queryUserBalance(order.getUserId()));
        return result;
    }
    
    @Override
    public boolean isSupport(String payWay) {
        return PayWay.BALANCE.name().equals(payWay);
    }
}

扩展性体现:明天老板说要加“刷脸支付”,我只需要:

  1. 新建FacePayWayProcess
  2. 实现3个抽象方法
  3. 完事!  不碰任何现有代码

🏭 智能工厂:系统的“最强大脑”


// 🤖 TradeOrderFactory.java - 支付界的“智能调度中心”
@Component
public class TradeOrderFactory {
    
    @Autowired
    private List<AbstractTradePayment> allPayments; // Spring自动收集所有支付方式
    
    public AbstractTradePayment getPayment(String payWay) {
        // 🎯 精准匹配:你要微信,绝不给你支付宝
        return allPayments.stream()
            .filter(payment -> payment.isSupport(payWay))
            .findFirst()
            .orElseThrow(() -> new RuntimeException("暂不支持该支付方式"));
    }
}

Spring的魔法@Autowired private List<...> 自动收集所有实现类,工厂只负责“查找”,不负责“管理”。

🚀 第四幕:业务方的“极致体验”

使用起来,简单到哭


// 🎪 业务层代码 - 干净得像刚擦过的玻璃
@Service
public class TradeOrderManageImpl implements ITradeOrderManage {
    
    private final TradeOrderFactory factory; // 注入智能工厂
    
    public WechatPayResult wechatPay(WechatPayParam param) {
        // ✨ 一行代码调用,底层自动走完整流程
        return (WechatPayResult) factory
            .getPayment(PayWay.WECHAT.name())
            .processPay(param);
    }
    
    public BalancePayResult balancePay(BalancePayParam param) {
        // 🔄 换支付方式?只是换个枚举值!
        return (BalancePayResult) factory
            .getPayment(PayWay.BALANCE.name())
            .processPay(param);
    }
}

测试代码,清晰明了


@Test
public void testWechatMemberPayment() {
    // 🎨 准备测试数据
    WechatPayParam param = WechatPayParam.builder()
        .userId(123L)
        .amount(new BigDecimal("199.00"))
        .orderName("年度VIP会员")
        .tradeBizType(TradeBizType.MEMBER)
        .payWay(PayWay.WECHAT)
        .wxOpenId("openid_123")
        .build();
    
    // 🚀 执行支付
    WechatPayResult result = tradeOrderManage.wechatPay(param);
    
    // ✅ 验证结果
    assertNotNull(result.getPayMessage());
    assertEquals("PAYING", result.getTradeStatus().name());
    log.info("微信会员支付测试通过!返回:{}", result);
}

📊 第五幕:架构的“降维打击”

传统方式 vs 我们的设计

维度传统if-else大法我们的三模式融合
新增支付方式修改巨型类,风险高新增类,零风险
代码行数/类3000+行50-100行
可读性需要通读全文看抽象类知流程
可测试性难以Mock所有分支每个策略独立测试
团队协作容易冲突每人负责不同策略
新人上手需要一周熟悉一小时看懂架构

🏗️ 系统的“弹性架构”


📦 支付系统架构图

          ┌─────────────────┐
          │   业务调用层     │ ← 简单API,开箱即用
          └────────┬────────┘
                   │
          ┌────────▼────────┐
          │  智能工厂 🏭    │ ← 自动路由,精准匹配  
          └────────┬────────┘
                   │
    ┌──────────────┼──────────────┐
    │              │              │
┌───▼────┐   ┌────▼────┐   ┌─────▼───┐
│微信支付 │   │ 支付宝  │   │余额支付 │ ← 独立策略,互不干扰
│策略类💚 │   │策略类💙 │   │策略类💛 │
└────────┘   └─────────┘   └─────────┘
    │              │              │
    └──────────────┼──────────────┘
                   │
          ┌────────▼────────┐
          │ 模板方法基类 📜  │ ← 统一流程,确保规范
          └─────────────────┘

🌈 第六幕:还能更优雅吗?当然!

生产级增强建议


// 1️⃣ 添加分布式锁,防止重复支付
@Slf4j
@Service  
public class TradeOrderCompleteManageImpl {
    
    // 🔐 从本地锁升级为分布式锁
    public void completePayTrade(BasePayResult result, TraderOrder order) {
        String lockKey = "PAY_LOCK:" + order.getTradeOrderNo();
        try {
            // 使用Redis分布式锁
            Boolean locked = redisTemplate.opsForValue()
                .setIfAbsent(lockKey, "LOCKED", 5, TimeUnit.MINUTES);
                
            if (Boolean.TRUE.equals(locked)) {
                // 安全的处理逻辑...
            }
        } finally {
            redisTemplate.delete(lockKey);
        }
    }
}

// 2️⃣ 添加监控埋点
public abstract class AbstractTradePayment {
    
    public BasePayResult processPay(BasePayParam order) {
        String metricName = "payment." + this.getClass().getSimpleName();
        Timer.Sample sample = Timer.start();
        
        try {
            // ... 原有逻辑
            sample.stop(Metrics.timer(metricName, "status", "success"));
            return result;
        } catch (Exception e) {
            sample.stop(Metrics.timer(metricName, "status", "error"));
            throw e;
        }
    }
}

🎭 处理支付回调的“优雅舞步”


// 支付成功后的业务处理也遵循同样模式
@Service
public class MemberTradeComplete extends AbstractTradeComplete<MemberOrder> {
    
    @Override
    public void successComplete(TraderOrder order, MemberOrder memberOrder) {
        // 🎁 支付成功:开通会员权益
        memberService.activeVip(memberOrder.getUserId(), 
            order.getSuccessTime());
        notifyService.sendSuccessMsg(order.getUserId(), "会员开通成功!");
        
        log.info("用户{}会员开通完成,订单:{}", 
            order.getUserId(), order.getTradeOrderNo());
    }
    
    @Override
    public void failComplete(TraderOrder order, MemberOrder memberOrder) {
        // 😢 支付失败:释放占用的会员名额
        memberService.releaseReservation(memberOrder.getUserId());
        notifyService.sendFailMsg(order.getUserId(), "支付失败,请重试");
    }
}

🎯 第七幕:为什么这个设计如此迷人?

💡 核心优势总结

  1. 开闭原则的典范
    对扩展开放:新增支付方式?加个类就行
    对修改关闭:绝不修改现有代码

  2. 各司其职的优雅

    • 模板类:我只关心流程
    • 策略类:我只专注实现
    • 工厂类:我只负责调度
  3. 新人友好的设计
    新同事第一天就能看懂:“哦,原来支付系统是这样工作的!”

  4. 测试的便利性
    每个支付方式可以单独测试,Mock成本极低

  5. 演化的可持续性
    系统会随着业务增长而“自然生长”,而不是“野蛮堆砌”

📚 最后:给你的“设计工具箱”

这个支付系统设计给了我们一个重要的启示:复杂度不是天生的,而是设计出来的。好的设计不是消灭复杂度,而是管理复杂度。

适用场景 checklist ✅

  • 你有多种相似但不同的算法/策略
  • 未来可能会有新的策略加入
  • 你希望避免庞大的条件语句
  • 团队需要清晰的职责划分
  • 系统需要长期维护和演进

🎁 彩蛋:完整源码获取

如果你想要:

  • ✅ 完整可运行的Spring Boot项目
  • ✅ 所有支付策略的实现代码
  • ✅ 数据库设计脚本
  • ✅ Postman测试集合
  • ✅ 详细的部署文档

欢迎关注我的公众号 SilkyStarter,回复关键词 「优雅支付」 获取完整源码。

在公众号里,我还会分享:

  • 🚀 微服务架构深度解析
  • 🎯 高并发系统设计实战
  • 🔧 代码重构的“艺术与科学”
  • 📈 从程序员到架构师的成长路径

源码 + 深度解析 + 持续更新 = 你的技术加速器


💬 灵魂提问

如果你来设计:

  1. 这个架构还能在哪些业务场景中复刻?
  2. 如果支付方式达到50种,这个设计还撑得住吗?
  3. 如何在这个基础上加入“支付路由”智能选择最优惠渠道?

欢迎在评论区分享你的高见!  让我们一起把代码写成诗 ✨