策略模式和工厂模式的区别?


面试考察点

  1. 核心意图区分:面试官不仅仅是想知道两种模式的定义差异,更是想看你能否一句话讲清各自的核心意图——策略模式解决 "怎么做" 的问题,工厂模式解决 "谁来创建" 的问题。

  2. 消除 if-else 的不同思路:两种模式都能消除 if-else,但消除的层面不同。能否讲清这个区别,是区分 "背过" 和 "理解了" 的关键。

  3. 组合使用能力:能否举例说明两者如何配合使用(策略模式 + 工厂模式 / 策略模式 + Spring 注入),这是加分项。

核心答案

先说核心区别

对比维度策略模式工厂模式
设计类型行为型创建型
核心意图封装不同的算法/行为,运行时灵活切换封装对象的创建过程,解耦客户端和具体类
解决的问题"同一件事,不同做法""不同对象,统一创建"
关注点怎么做(行为选择)谁来创建(对象创建)
典型场景支付方式选择、排序算法切换日志框架选择、数据库连接创建
消除 if-else 的层面消除业务逻辑中的分支判断消除对象创建中的分支判断

一句话区分:策略模式让你灵活切换 "做事的方式",工厂模式让你不用关心 "对象怎么创建的"

上面的图展示了两者的核心区别和配合关系:

  • 策略模式Context 持有 Strategy 的引用,运行时切换不同的策略对象来改变行为。客户端需要自己知道有哪些策略可选。
  • 工厂模式Client 只跟 Factory 打交道,不知道具体创建了哪个产品。客户端只需要告诉工厂 "我要什么",创建细节被完全隐藏。
  • 配合使用:工厂负责创建策略对象,策略负责执行具体逻辑。两者分工明确。

深度解析

一、用同一个场景对比两种模式

用 "支付方式选择" 这个场景,分别用策略模式和工厂模式实现,对比最直观。

策略模式实现

// 策略接口
public interface PaymentStrategy {
    void pay(BigDecimal amount);
}

// 支付宝策略
public class AlipayStrategy implements PaymentStrategy {
    @Override
    public void pay(BigDecimal amount) {
        System.out.println("支付宝支付:" + amount + " 元");
    }
}

// 微信策略
public class WechatStrategy implements PaymentStrategy {
    @Override
    public void pay(BigDecimal amount) {
        System.out.println("微信支付:" + amount + " 元");
    }
}

// 上下文:持有策略引用
public class PaymentContext {

    private PaymentStrategy strategy;

    // 运行时切换策略
    public void setStrategy(PaymentStrategy strategy) {
        this.strategy = strategy;
    }

    public void pay(BigDecimal amount) {
        strategy.pay(amount); // 委托给策略对象
    }
}

使用:

PaymentContext ctx = new PaymentContext();

ctx.setStrategy(new AlipayStrategy());
ctx.pay(new BigDecimal("100")); // 支付宝支付:100 元

// 运行时切换策略
ctx.setStrategy(new WechatStrategy());
ctx.pay(new BigDecimal("200")); // 微信支付:200 元

工厂模式实现

// 产品接口(和上面的策略接口一样)
public interface Payment {
    void pay(BigDecimal amount);
}

// 具体产品
public class AlipayPayment implements Payment { /* 同上 */ }
public class WechatPayment implements Payment { /* 同上 */ }

// 工厂:封装创建逻辑
public class PaymentFactory {

    public static Payment create(String type) {
        switch (type) {
            case "alipay":  return new AlipayPayment();
            case "wechat":  return new WechatPayment();
            default: throw new IllegalArgumentException("未知支付方式");
        }
    }
}

使用:

Payment payment = PaymentFactory.create("alipay");
payment.pay(new BigDecimal("100")); // 支付宝支付:100 元

看到区别了吗?

  • 策略模式PaymentContext 持有策略的引用,可以在运行时动态切换。客户端直接操作的是策略对象。
  • 工厂模式PaymentFactory 只负责创建对象,创建完就不管了。客户端拿到的是产品对象。

二、消除 if-else 的层面不同

两种模式都能消除 if-else,但消除的位置不同:

没有模式时的代码

public void pay(String type, BigDecimal amount) {
    if ("alipay".equals(type)) {
        // 支付宝支付逻辑(可能几十行)
        System.out.println("调用支付宝 API...");
        System.out.println("支付宝支付:" + amount + " 元");
    } else if ("wechat".equals(type)) {
        // 微信支付逻辑(可能几十行)
        System.out.println("调用微信 API...");
        System.out.println("微信支付:" + amount + " 元");
    } else if ("unionpay".equals(type)) {
        // 银联支付逻辑(可能几十行)
        System.out.println("调用银联 API...");
        System.out.println("银联支付:" + amount + " 元");
    }
}

策略模式消除的是业务逻辑中的 if-else

// 每种支付方式独立成类,业务方法变成一行
public void pay(BigDecimal amount) {
    strategy.pay(amount); // 没有任何 if-else
}

工厂模式消除的是对象创建中的 if-else(但工厂内部可能还是有):

// 工厂内部用 Map 优化
private static final Map<String, Supplier<Payment>> registry = new HashMap<>();

static {
    registry.put("alipay", AlipayPayment::new);
    registry.put("wechat", WechatPayment::new);
}

public static Payment create(String type) {
    return registry.getOrDefault(type, () -> { throw new IllegalArgumentException(); }).get();
}

简单说:策略模式把 if-else 从业务逻辑中移走了,工厂模式把 if-else 从对象创建中移走了

三、两者配合使用

在实际项目中,策略模式和工厂模式经常配合使用。用一个更贴近生产的例子:

// 策略接口
public interface DiscountStrategy {
    BigDecimal calculate(BigDecimal price);
}

// 满减策略
@Component("fullReduction")
public class FullReductionStrategy implements DiscountStrategy {
    @Override
    public BigDecimal calculate(BigDecimal price) {
        return price.compareTo(new BigDecimal("100")) >= 0
            ? price.subtract(new BigDecimal("20"))
            : price;
    }
}

// 打折策略
@Component("discount")
public class DiscountStrategyImpl implements DiscountStrategy {
    @Override
    public BigDecimal calculate(BigDecimal price) {
        return price.multiply(new BigDecimal("0.8"));
    }
}

// 无优惠策略
@Component("noDiscount")
public class NoDiscountStrategy implements DiscountStrategy {
    @Override
    public BigDecimal calculate(BigDecimal price) {
        return price;
    }
}

用 Spring 容器当工厂,通过 Bean 名称获取策略:

@Service
public class OrderService {

    @Autowired
    private Map<String, DiscountStrategy> strategyMap; // Spring 自动注入所有策略

    public BigDecimal calculatePrice(BigDecimal price, String discountType) {
        DiscountStrategy strategy = strategyMap.get(discountType); // 工厂:获取策略
        return strategy.calculate(price);                          // 策略:执行计算
    }
}

这里 Spring 的依赖注入充当了工厂的角色(根据 Bean 名称获取对象),DiscountStrategy 的各个实现就是策略。工厂负责 "找到正确的策略",策略负责 "执行正确的计算"。各司其职,完美配合。

四、实际应用对比

场景用策略模式用工厂模式
支付方式选择✅ 不同支付算法可运行时切换只解决创建,不解决切换
日志框架切换可以,但通常不需要运行时切换✅ 创建具体日志实现
排序算法选择✅ 运行时根据数据特点选排序创建排序对象
数据库连接创建不适用✅ 根据配置创建不同连接
促销折扣计算✅ 不同折扣规则可灵活切换配合策略模式获取策略对象

面试高频追问

  1. 策略模式和状态模式有什么区别?

    • 策略模式中客户端主动选择策略;状态模式中状态对象自动切换状态,客户端不感知。策略之间互相独立,状态之间有转换关系。
  2. 策略模式有什么缺点?

    • 客户端必须知道所有策略的区别,才能选择合适的策略。策略对象增多时,类的数量也会变多。
  3. 如何避免策略模式中大量的 if-else 来选择策略?

    • Map<String, Strategy> 注册表 + Spring 自动注入,通过 key 直接获取策略,完全消除 if-else

常见面试变体

  • "策略模式和工厂模式能一起用吗?怎么用?"
  • "如何消除业务代码中的大量 if-else?"
  • "策略模式和状态模式的区别?"
  • "Spring 中哪里用到了策略模式?"

记忆口诀

核心区别:策略管 "怎么做"(行为),工厂管 "谁来建"(创建)。

消除 if-else:策略消灭业务分支,工厂消灭创建分支。

配合使用:工厂造策略,策略做业务;工厂负责找,策略负责干。

总结

策略模式和工厂模式的核心区别就是 "行为选择" vs "对象创建"。面试时先用一句话点明区别,再用支付场景对比两种实现,最后展示两者配合使用的最佳实践(Spring 注入 + 策略 Map)。能把 "工厂负责找策略,策略负责执行" 这句话讲清楚,面试官就知道你不只是背了概念,而是真的在项目中用过。