设计模式综合实战(一):需求分析与架构设计

基于策略+工厂模式实现支付系统

说实话,每次带新人做项目,我最怕听到的一句话就是:「这个支付系统很简单,不就是调个接口嘛。」

嗯,说这话的人,十有八九会在上线前夜被产品经理追着改需求。我经历过太多次了——今天加个微信支付,明天要支持花呗分期,后天又来了个跨境支付。如果你一开始没想好架构,后面就是无尽的加班和重构。

所以这一章,咱们就来聊聊怎么用设计模式,把支付系统做得既灵活又稳定。

需求分析:先搞清楚要做什么

做架构设计之前,我习惯先列需求。不是那种「用户能付款」的废话,而是真正影响技术选型的点。

  • 多支付渠道:微信支付、支付宝、银联、PayPal……未来可能还有新的
  • 支付流程不同:有的需要扫码,有的需要跳转,有的直接扣款
  • 参数差异大:每个渠道的请求参数、签名方式、回调格式都不一样
  • 扩展性要求:加一个新支付方式,不能改已有代码
  • 运行时切换:用户选什么支付方式,系统就执行对应的逻辑

你想想看,如果把这些逻辑全写在一个类里,那会是什么样子?

一个巨大的 switch-case,里面塞满各种 if-else。每次加新渠道,都要改这个类。测试要回归所有分支。我见过一个项目,支付类有 3000 多行,没人敢动。

我曾经接手过一个遗留系统,支付逻辑全写在一个 Service 里。加一个「云闪付」功能,改了三周,还引入两个线上 bug。从那以后,我对「面向过程写支付」深恶痛绝。

架构设计:策略模式 + 工厂模式

怎么解决?说白了就两招:

  • 策略模式:把每种支付方式封装成独立的策略类
  • 工厂模式:根据用户选择的支付方式,创建对应的策略对象

这样,每种支付逻辑互不干扰。加新渠道,就是加一个新类。不改旧代码,符合开闭原则。

先画个图,理清关系

我个人习惯,动手写代码前先画个结构图。下面这个 SVG 就是支付系统的核心架构:

支付系统架构图(策略+工厂模式) 客户端(Client) 支付工厂(PaymentFactory) 支付策略接口(IPaymentStrategy) 微信支付策略 支付宝策略 银联支付策略

这个图你看懂了吗?客户端不直接依赖具体支付类,它只跟工厂打交道。工厂根据参数,返回对应的策略对象。客户端调用策略对象的 pay() 方法,具体怎么支付,策略自己知道。

代码实现:从接口开始

好,咱们动手写代码。先从策略接口开始:

// 支付策略接口
class IPaymentStrategy {
public:
    virtual ~IPaymentStrategy() = default;
    
    // 核心支付方法
    virtual bool pay(double amount, const std::string& orderId) = 0;
    
    // 获取支付方式名称
    virtual std::string getPaymentName() const = 0;
};

接口很简单,就两个方法。但注意,实际项目中 pay() 的参数会复杂得多——可能包含商品信息、用户信息、回调地址等。这里为了演示,我简化了。

具体策略实现

接下来,实现微信支付和支付宝:

// 微信支付策略
class WeChatPay : public IPaymentStrategy {
public:
    bool pay(double amount, const std::string& orderId) override {
        // 微信支付的业务逻辑
        std::cout << "[微信支付] 订单: " << orderId 
                  << ", 金额: " << amount << " 元" << std::endl;
        std::cout << "生成二维码..." << std::endl;
        std::cout << "等待用户扫码..." << std::endl;
        // 模拟支付成功
        return true;
    }
    
    std::string getPaymentName() const override {
        return "微信支付";
    }
};

// 支付宝策略
class AliPay : public IPaymentStrategy {
public:
    bool pay(double amount, const std::string& orderId) override {
        std::cout << "[支付宝] 订单: " << orderId 
                  << ", 金额: " << amount << " 元" << std::endl;
        std::cout << "跳转到支付宝收银台..." << std::endl;
        return true;
    }
    
    std::string getPaymentName() const override {
        return "支付宝";
    }
};

你看,每个策略只关心自己的逻辑。微信支付要生成二维码,支付宝要跳转页面。互不干扰。

工厂模式:创建策略对象

策略写好了,谁来创建它们?工厂模式上场:

// 支付工厂
class PaymentFactory {
public:
    static std::unique_ptr<IPaymentStrategy> createPayment(const std::string& type) {
        if (type == "wechat") {
            return std::make_unique<WeChatPay>();
        } else if (type == "alipay") {
            return std::make_unique<AliPay>();
        } else if (type == "unionpay") {
            return std::make_unique<UnionPay>();
        } else {
            throw std::invalid_argument("不支持的支付方式: " + type);
        }
    }
};
我个人习惯用 std::unique_ptr 管理策略对象的生命周期。这样工厂创建的对象,客户端用完自动释放,不会内存泄漏。如果你用原始指针,记得要 delete,但很容易忘。

客户端使用

最后,看看客户端怎么用:

int main() {
    // 用户选择了微信支付
    std::string paymentType = "wechat";
    
    // 通过工厂获取策略对象
    auto payment = PaymentFactory::createPayment(paymentType);
    
    // 执行支付
    bool success = payment->pay(99.9, "ORDER2024001");
    
    if (success) {
        std::cout << "支付成功!使用方式: " 
                  << payment->getPaymentName() << std::endl;
    }
    
    return 0;
}

输出结果:

[微信支付] 订单: ORDER2024001, 金额: 99.9 元
生成二维码...
等待用户扫码...
支付成功!使用方式: 微信支付

扩展性验证

现在产品经理说:「我们要加银联支付!」

你只需要做两件事:

  1. 写一个 UnionPay 类,继承 IPaymentStrategy
  2. 在工厂的 createPayment 里加一个 else-if 分支

仅此而已。已有的 WeChatPay、AliPay 代码,一行都不用改。测试也只需要测新加的银联部分。

这就是设计模式的力量

  • 策略模式让每种支付逻辑独立
  • 工厂模式让对象的创建集中管理
  • 两者结合,系统既灵活又稳定

避坑指南

最后,分享几个我踩过的坑:

  • 不要用字符串硬编码:工厂里用 "wechat"、"alipay" 这种字符串,容易拼错。我建议用枚举或者 constexpr 常量。
  • 注意线程安全:如果工厂在多线程环境下被调用,确保 createPayment 是线程安全的。目前这个实现没问题,因为没共享状态。
  • 策略对象不要太大:每个策略只做自己的事。如果某个策略需要大量配置,考虑用建造者模式配合。

嗯,这一章就到这里。代码虽然简单,但背后的思想值得反复琢磨。下一章咱们会在这个基础上,加入更多实战细节——比如异步回调、重试机制、日志埋点等。


公众号:蓝海资料掘金营,微信deep3321