1. 工厂模式与策略模式实战解析
最近在重构一个电商促销系统时,我深刻体会到设计模式的重要性。当促销策略从最初的3种扩展到12种,当商品类型从普通商品延伸到服务类虚拟商品,如果没有良好的设计模式支撑,代码很快就会变成难以维护的"意大利面条"。今天我们就来聊聊在实际开发中最常用的两种设计模式——工厂模式和策略模式,以及它们的组合使用技巧。
工厂模式就像是一个智能的生产车间,你告诉它"我需要一个A型产品",它就会自动给你生产出符合要求的对象,而不用关心具体的生产过程。策略模式则像是可插拔的算法模块,比如支付系统可以选择支付宝策略、微信支付策略或者银联策略,运行时可以自由切换。这两种模式经常配合使用,比如用工厂创建具体的策略实例。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 工厂模式深度剖析
2.1 简单工厂模式实现
先来看一个最简单的工厂实现——促销计算器工厂:
java复制public class DiscountFactory {
public static DiscountCalculator createCalculator(String type) {
switch(type) {
case "FULL_100_MINUS_20":
return new Full100Minus20Calculator();
case "SECOND_HALF_PRICE":
return new SecondHalfPriceCalculator();
case "GROUP_BUY":
return new GroupBuyCalculator();
default:
throw new IllegalArgumentException("未知的折扣类型");
}
}
}
这个工厂虽然简单,但已经解决了对象创建的耦合问题。调用方只需要知道促销类型,不需要了解具体计算器的实现细节。
注意:简单工厂违反开闭原则,新增类型需要修改工厂类。当促销类型频繁变化时,建议改用工厂方法模式。
2.2 工厂方法模式进阶
工厂方法模式通过引入抽象工厂来解决扩展性问题:
java复制public interface DiscountFactory {
DiscountCalculator createCalculator();
}
public class Full100Minus20Factory implements DiscountFactory {
@Override
public DiscountCalculator createCalculator() {
return new Full100Minus20Calculator();
}
}
每个促销类型都有自己的工厂类,新增类型时只需添加新的工厂类,不需要修改现有代码。
2.3 抽象工厂模式实战
当需要创建一系列相关对象时,可以使用抽象工厂。比如电商系统中的国际站需要支持多币种:
java复制public interface InternationalFactory {
CurrencyConverter createCurrencyConverter();
TaxCalculator createTaxCalculator();
}
public class USFactory implements InternationalFactory {
@Override
public CurrencyConverter createCurrencyConverter() {
return new USDConverter();
}
@Override
public TaxCalculator createTaxCalculator() {
return new USTaxCalculator();
}
}
3. 策略模式灵活应用
3.1 基础策略模式实现
策略模式的核心是将算法封装成独立的类。以支付系统为例:
java复制public interface PaymentStrategy {
void pay(BigDecimal amount);
}
public class AlipayStrategy implements PaymentStrategy {
@Override
public void pay(BigDecimal amount) {
// 调用支付宝SDK
}
}
public class PaymentContext {
private PaymentStrategy strategy;
public PaymentContext(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void executePayment(BigDecimal amount) {
strategy.pay(amount);
}
}
3.2 策略模式与枚举的结合
Java枚举是实现策略模式的优雅方式:
java复制public enum ShippingStrategy {
STANDARD {
@Override
public BigDecimal calculate(BigDecimal weight) {
return weight.multiply(new BigDecimal("5"));
}
},
EXPRESS {
@Override
public BigDecimal calculate(BigDecimal weight) {
return weight.multiply(new BigDecimal("8")).add(new BigDecimal("10"));
}
};
public abstract BigDecimal calculate(BigDecimal weight);
}
3.3 策略模式动态切换
策略模式的优势在于运行时可以动态切换策略:
java复制public class TrafficFeeCalculator {
private TrafficFeeStrategy strategy;
public void setStrategy(TrafficFeeStrategy strategy) {
this.strategy = strategy;
}
public BigDecimal calculateFee(int distance) {
return strategy.calculate(distance);
}
}
// 使用示例
TrafficFeeCalculator calculator = new TrafficFeeCalculator();
calculator.setStrategy(new BusStrategy());
BigDecimal fee = calculator.calculateFee(10);
4. 工厂模式与策略模式组合使用
4.1 策略对象的创建优化
直接用new创建策略实例会导致耦合,可以用工厂模式改进:
java复制public class PaymentStrategyFactory {
public static PaymentStrategy createStrategy(String type) {
switch(type) {
case "ALIPAY":
return new AlipayStrategy();
case "WECHAT":
return new WechatPayStrategy();
default:
throw new IllegalArgumentException("未知支付类型");
}
}
}
// 使用示例
PaymentStrategy strategy = PaymentStrategyFactory.createStrategy("ALIPAY");
PaymentContext context = new PaymentContext(strategy);
context.executePayment(new BigDecimal("100"));
4.2 反射增强的工厂模式
通过反射可以实现更灵活的工厂:
java复制public class ReflectionStrategyFactory {
private static final String PACKAGE = "com.example.strategy.";
public static PaymentStrategy createStrategy(String type) {
try {
return (PaymentStrategy) Class.forName(PACKAGE + type + "Strategy")
.newInstance();
} catch (Exception e) {
throw new RuntimeException("创建策略失败", e);
}
}
}
注意:反射虽然灵活但性能较差,可以考虑缓存Class对象或者使用预编译技术优化。
4.3 Spring集成方案
在Spring环境中,可以充分利用IoC容器:
java复制@Component
public class StrategyFactory {
@Autowired
private Map<String, PaymentStrategy> strategyMap;
public PaymentStrategy getStrategy(String type) {
return strategyMap.get(type + "Strategy");
}
}
// 策略实现类
@Component
public class AlipayStrategy implements PaymentStrategy {
// 实现代码
}
Spring会自动将所有PaymentStrategy实现注入到strategyMap中,key为bean名称。
5. 实战中的经验与陷阱
5.1 模式选择的考量因素
选择工厂模式还是策略模式,或者组合使用,需要考虑以下因素:
- 变化频率:如果对象创建逻辑经常变化,用工厂模式隔离变化
- 算法数量:策略模式适合算法数量较多且需要动态切换的场景
- 性能要求:反射创建的策略对象需要考虑性能开销
- 团队习惯:保持团队统一的设计风格很重要
5.2 常见问题排查
问题1:策略执行结果不符合预期
- 检查策略是否被正确设置
- 确认工厂返回的是正确的策略实例
- 调试策略类中的算法逻辑
问题2:新增策略导致工厂需要修改
- 考虑改用反射机制
- 或者使用配置文件驱动工厂
问题3:策略之间有状态共享
- 确保策略类是无状态的
- 如果需要状态,考虑使用上下文对象传递
5.3 性能优化技巧
- 对象复用:对于无状态的策略对象,可以缓存实例
- 预编译:使用注解处理器生成工厂代码
- 懒加载:延迟创建策略对象直到真正需要时
- 并行计算:不同策略可以并行执行时使用多线程
6. 设计模式在框架中的应用
6.1 MyBatis中的类型处理器
MyBatis的类型处理器就是策略模式的典型应用,处理枚举类型时特别有用:
java复制public enum UserStatus {
ACTIVE, INACTIVE, LOCKED
}
public class UserStatusHandler extends BaseTypeHandler<UserStatus> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
UserStatus parameter, JdbcType jdbcType) {
ps.setString(i, parameter.name());
}
@Override
public UserStatus getNullableResult(ResultSet rs, String columnName) {
return UserStatus.valueOf(rs.getString(columnName));
}
}
6.2 Spring Security的认证策略
Spring Security使用策略模式来实现多种认证方式:
java复制public interface AuthenticationProvider {
Authentication authenticate(Authentication authentication);
boolean supports(Class<?> authentication);
}
// 实现类示例
public class DaoAuthenticationProvider implements AuthenticationProvider {
// 实现细节
}
6.3 JUnit的测试执行策略
JUnit使用策略模式来决定如何执行测试:
java复制public interface TestExecutionStrategy {
void execute(TestExecutionContext context);
}
public class DefaultTestExecutionStrategy implements TestExecutionStrategy {
// 实现代码
}
在实际项目中,我发现合理使用工厂模式和策略模式可以带来以下好处:
- 代码更易于维护和扩展
- 业务逻辑更清晰
- 单元测试更容易编写
- 团队协作更顺畅
最后分享一个小技巧:在IDE中为策略接口添加@FunctionalInterface注解,这样可以使用lambda表达式简化策略实现,特别是在策略逻辑简单的情况下,代码会更加简洁。
