策略模式和工厂模式的区别?
面试考察点
-
核心意图区分:面试官不仅仅是想知道两种模式的定义差异,更是想看你能否一句话讲清各自的核心意图——策略模式解决 "怎么做" 的问题,工厂模式解决 "谁来创建" 的问题。
-
消除
if-else的不同思路:两种模式都能消除if-else,但消除的层面不同。能否讲清这个区别,是区分 "背过" 和 "理解了" 的关键。 -
组合使用能力:能否举例说明两者如何配合使用(策略模式 + 工厂模式 / 策略模式 + 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 的各个实现就是策略。工厂负责 "找到正确的策略",策略负责 "执行正确的计算"。各司其职,完美配合。
四、实际应用对比
| 场景 | 用策略模式 | 用工厂模式 |
|---|---|---|
| 支付方式选择 | ✅ 不同支付算法可运行时切换 | 只解决创建,不解决切换 |
| 日志框架切换 | 可以,但通常不需要运行时切换 | ✅ 创建具体日志实现 |
| 排序算法选择 | ✅ 运行时根据数据特点选排序 | 创建排序对象 |
| 数据库连接创建 | 不适用 | ✅ 根据配置创建不同连接 |
| 促销折扣计算 | ✅ 不同折扣规则可灵活切换 | 配合策略模式获取策略对象 |
面试高频追问
-
策略模式和状态模式有什么区别?
- 策略模式中客户端主动选择策略;状态模式中状态对象自动切换状态,客户端不感知。策略之间互相独立,状态之间有转换关系。
-
策略模式有什么缺点?
- 客户端必须知道所有策略的区别,才能选择合适的策略。策略对象增多时,类的数量也会变多。
-
如何避免策略模式中大量的
if-else来选择策略?- 用
Map<String, Strategy>注册表 + Spring 自动注入,通过 key 直接获取策略,完全消除if-else。
- 用
常见面试变体
- "策略模式和工厂模式能一起用吗?怎么用?"
- "如何消除业务代码中的大量
if-else?" - "策略模式和状态模式的区别?"
- "Spring 中哪里用到了策略模式?"
记忆口诀
核心区别:策略管 "怎么做"(行为),工厂管 "谁来建"(创建)。
消除 if-else:策略消灭业务分支,工厂消灭创建分支。
配合使用:工厂造策略,策略做业务;工厂负责找,策略负责干。
总结
策略模式和工厂模式的核心区别就是 "行为选择" vs "对象创建"。面试时先用一句话点明区别,再用支付场景对比两种实现,最后展示两者配合使用的最佳实践(Spring 注入 + 策略 Map)。能把 "工厂负责找策略,策略负责执行" 这句话讲清楚,面试官就知道你不只是背了概念,而是真的在项目中用过。
