面试官最爱问的设计题:动态支付系统设计(策略模式 + 工厂模式 + Spring自动注册)

3 阅读5分钟

这道题其实是 面试中非常经典的面向对象设计题。面试官通过这道题主要考察三个能力:

1️⃣ 是否理解 面向对象设计( OOP 2️⃣ 是否掌握 设计模式 3️⃣ 是否能写出 可扩展的系统代码

下面我从 场景 → 问题 → 设计 → 策略模式 → 工厂模式 → 最终代码结构 一步一步讲清楚。


一、题目场景:动态选择支付方式

假设你在开发一个电商系统。

用户支付时可以选择:

  • 支付宝
  • 微信
  • 银行卡
  • Apple Pay
  • 未来可能增加更多支付方式

用户请求:

POST /pay
{
  orderId: 123,
  payType: "ALIPAY"
}

系统需要:

根据 payType 调用不同支付逻辑

例如:

ALIPAY  -> AliPayService
WECHAT  -> WechatPayService
BANK    -> BankPayService

二、最差的写法(很多人第一反应)

很多人会写:

if(payType.equals("ALIPAY")){
    aliPay();
}else if(payType.equals("WECHAT")){
    wechatPay();
}else if(payType.equals("BANK")){
    bankPay();
}

问题:

❌ 违反 开闭原则

如果新增支付方式:

ApplePay

就要改代码:

if else +1

如果支付方式越来越多:

100种支付

代码会变成:

巨型 if else

维护灾难。


三、正确思路:使用策略模式

核心思想:

不同的算法/行为封装成不同类,在运行时选择。

支付方式就是不同 支付策略


四、策略模式结构

策略模式结构:

            PaymentStrategy
                  ↑
        ┌─────────┼─────────┐
     AliPay    WechatPay   BankPay

每种支付方式都是一个 策略实现类


第一步:定义支付接口

public interface PaymentStrategy {
    void pay(Order order);
}

第二步:实现不同支付策略

支付宝:

public class AliPay implements PaymentStrategy {

    @Override
    public void pay(Order order) {
        System.out.println("支付宝支付");
    }

}

微信:

public class WechatPay implements PaymentStrategy {

    @Override
    public void pay(Order order) {
        System.out.println("微信支付");
    }

}

银行卡:

public class BankPay implements PaymentStrategy {

    @Override
    public void pay(Order order) {
        System.out.println("银行卡支付");
    }

}

五、如何动态选择策略?

问题来了:

用户选择支付方式时,如何找到对应策略?

例如:

payType = "ALIPAY"

如何拿到:

AliPay

这时候就需要:

工厂模式


六、工厂模式

工厂模式作用:

负责创建对象,而不是业务代码自己 new。

也就是:

PaymentFactory

负责:

返回对应的支付策略

工厂实现

public class PaymentFactory {

    private static Map<String, PaymentStrategy> strategyMap = new HashMap<>();

    static {
        strategyMap.put("ALIPAY", new AliPay());
        strategyMap.put("WECHAT", new WechatPay());
        strategyMap.put("BANK", new BankPay());
    }

    public static PaymentStrategy getStrategy(String payType) {
        return strategyMap.get(payType);
    }

}

七、业务调用流程

业务代码:

public class PaymentService {

    public void pay(String payType, Order order) {

        PaymentStrategy strategy = PaymentFactory.getStrategy(payType);

        strategy.pay(order);
    }

}

执行流程:

用户选择支付方式
        ↓
PaymentFactory
        ↓
获取策略对象
        ↓
执行支付逻辑

八、完整结构

系统结构:

PaymentStrategy
      ↑
 ┌────┼─────┐
AliPay WechatPay BankPay

PaymentFactory

PaymentService

职责:

组件职责
PaymentStrategy定义支付接口
AliPay具体策略
WechatPay具体策略
PaymentFactory创建策略
PaymentService业务调用

九、为什么这是好设计?

优点:

1 开闭原则

新增支付方式:

ApplePay

只需要:

新增类

不用修改旧代码。


2 解耦

业务代码:

PaymentService

不需要知道:

AliPay
WechatPay

具体实现。


3 可扩展

未来可以扩展:

风控
日志
限流


十、面试回答模板

如果面试再问这题,可以这样回答:

我会使用策略模式封装不同的支付方式,每种支付方式实现统一的支付接口,例如 AliPay、WechatPay。

然后使用工厂模式根据用户选择的 payType 返回对应策略对象,业务代码只需要调用 strategy.pay()。

这样设计可以避免大量 if-else,提高系统扩展性。


十一、面试官真正考察什么

这道题考察的是:

OOP设计
设计模式
系统扩展能力
代码结构

很多大厂面试都会追问的升级版问题

如果支付方式有 100种,工厂里 map.put() 会不会很难维护?

这个问题的答案其实涉及 Spring + 自动注册策略模式,也是很多大厂喜欢问的设计题。

这是一个 非常经典的大厂追问问题,很多面试官在你回答完 策略模式 + 工厂模式 后都会继续问:

如果支付方式有 100种,工厂里 map.put() 会不会很难维护?

答案是:是的,会很难维护。

原因是你的代码会变成这样:

static {
    strategyMap.put("ALIPAY", new AliPay());
    strategyMap.put("WECHAT", new WechatPay());
    strategyMap.put("BANK", new BankPay());
    strategyMap.put("APPLEPAY", new ApplePay());
    strategyMap.put("UNIONPAY", new UnionPay());
    ...
}

如果有 100种支付方式

  • 工厂类会非常大
  • 每新增一种支付方式都要 修改工厂代码
  • 违反 开闭原则 Open-Closed Principle

所以需要一种更好的设计:

新增策略类
↓
系统自动注册
↓
无需修改工厂

这就是常见的 自动注册策略模式


一、优化目标

我们希望达到:

新增支付方式
↓
只新增一个类
↓
系统自动识别

不需要:

修改工厂类

二、解决方案:使用 Spring 自动注入(最常见)

在 Spring 项目中可以利用 IOC 容器

Spring 可以自动把所有实现类注入到 Map 里。


第一步:定义策略接口

public interface PaymentStrategy {

    String getPayType();

    void pay(Order order);

}

第二步:实现策略

支付宝:

@Component
public class AliPayStrategy implements PaymentStrategy {

    @Override
    public String getPayType() {
        return "ALIPAY";
    }

    @Override
    public void pay(Order order) {
        System.out.println("支付宝支付");
    }
}

微信:

@Component
public class WechatPayStrategy implements PaymentStrategy {

    @Override
    public String getPayType() {
        return "WECHAT";
    }

    @Override
    public void pay(Order order) {
        System.out.println("微信支付");
    }
}

第三步:自动收集策略

@Service
public class PaymentService {

    private Map<String, PaymentStrategy> strategyMap = new HashMap<>();

    @Autowired
    public PaymentService(List<PaymentStrategy> strategies) {
        for (PaymentStrategy strategy : strategies) {
            strategyMap.put(strategy.getPayType(), strategy);
        }
    }

    public void pay(String payType, Order order) {
        PaymentStrategy strategy = strategyMap.get(payType);
        strategy.pay(order);
    }

}

Spring 会自动把:

AliPayStrategy
WechatPayStrategy
BankPayStrategy
...

全部注入进来。


三、结构图

系统结构变成:

PaymentStrategy
       ↑
 ┌─────┼─────┬─────┐
AliPay  WechatPay BankPay ...

Spring IOCList<PaymentStrategy>
      ↓
Map<String,Strategy>

四、这样有什么好处

1 新增支付方式零修改

新增:

@Component
class ApplePayStrategy implements PaymentStrategy

系统自动识别。

不需要改:

PaymentService

2 符合开闭原则

系统:

对扩展开放
对修改关闭

3 工厂逻辑消失

Spring 已经替代了 工厂模式


五、面试回答模板

如果面试官问:

如果有100种支付方式,工厂类会不会很难维护?

你可以这样回答:

如果支付方式很多,直接在工厂类中 map.put() 会导致代码难维护,并且违反开闭原则。

在实际项目中可以使用 Spring 的依赖注入机制,将所有 PaymentStrategy 的实现类自动注入为一个 ListMap,然后在初始化时动态构建策略映射。

这样新增支付方式时只需要新增一个策略类即可,无需修改原有代码。

这就是 比较标准的大厂回答


六、面试官真正想听什么

这道追问本质是考察:

开闭原则
IOC
Spring自动装配
可扩展架构

如果你能说出:

Spring自动注入策略

基本会 明显加分