1. 策略模式在Java多实体操作中的实战价值
上周重构一个老项目时,我面对这样一个典型场景:系统需要处理订单、用户、商品三种完全不同类型的实体对象,但它们的保存、验证、日志记录等操作流程却高度相似。如果为每个实体都写一套重复代码,不仅维护困难,新加实体时还得继续复制粘贴。这时候策略模式(Strategy Pattern)就成了我的救命稻草。
策略模式的核心在于定义算法族,分别封装起来,使它们可以互相替换。这种模式让算法的变化独立于使用算法的客户端。在我们这个场景中,"保存策略"、"验证策略"、"日志策略"就是不同的算法族,而订单、用户、商品则是使用这些策略的客户端。通过这种设计,当需要新增一个"促销活动"实体时,我只需要定义它的数据结构,现有的策略实现可以直接复用。
经验之谈:策略模式特别适合处理那些"行为相似但实现不同"的场景。我在电商系统中用策略模式统一处理过支付方式(支付宝、微信、银联),在内容平台统一处理过不同类型的审核流程(文字、图片、视频),效果都非常好。
2. 通用操作场景的策略模式设计
2.1 基础架构搭建
首先定义我们的策略接口,这是整个模式的核心。以保存操作为例:
java复制public interface SaveStrategy<T> {
void validate(T entity); // 验证逻辑
void preProcess(T entity); // 保存前处理
void executeSave(T entity); // 实际保存操作
void postProcess(T entity); // 保存后处理
}
然后为不同实体实现具体策略。比如订单保存策略:
java复制public class OrderSaveStrategy implements SaveStrategy<Order> {
@Override
public void validate(Order order) {
if(order.getItems().isEmpty()) {
throw new ValidationException("订单商品不能为空");
}
// 其他验证规则...
}
@Override
public void executeSave(Order order) {
orderRepository.save(order);
inventoryService.reduceStock(order.getItems()); // 扣减库存
}
// 其他方法实现...
}
2.2 策略上下文封装
为了让客户端代码更简洁,我们引入策略上下文类:
java复制public class OperationContext<T> {
private SaveStrategy<T> saveStrategy;
private ValidateStrategy<T> validateStrategy;
private LogStrategy<T> logStrategy;
public void executeSave(T entity) {
validateStrategy.validate(entity);
saveStrategy.preProcess(entity);
saveStrategy.executeSave(entity);
saveStrategy.postProcess(entity);
logStrategy.logOperation("save", entity);
}
// 策略setter方法
public void setSaveStrategy(SaveStrategy<T> saveStrategy) {
this.saveStrategy = saveStrategy;
}
// 其他策略setter...
}
使用时的客户端代码变得极其简洁:
java复制OperationContext<Order> orderContext = new OperationContext<>();
orderContext.setSaveStrategy(new OrderSaveStrategy());
orderContext.setValidateStrategy(new OrderValidateStrategy());
orderContext.executeSave(newOrder);
2.3 策略工厂优化
随着策略增多,我们可以引入工厂模式管理策略实例:
java复制public class StrategyFactory {
private static Map<Class<?>, SaveStrategy<?>> saveStrategies = new HashMap<>();
static {
saveStrategies.put(Order.class, new OrderSaveStrategy());
saveStrategies.put(User.class, new UserSaveStrategy());
saveStrategies.put(Product.class, new ProductSaveStrategy());
}
@SuppressWarnings("unchecked")
public static <T> SaveStrategy<T> getSaveStrategy(Class<T> entityType) {
return (SaveStrategy<T>) saveStrategies.get(entityType);
}
}
这样客户端代码进一步简化:
java复制OperationContext<Order> context = new OperationContext<>();
context.setSaveStrategy(StrategyFactory.getSaveStrategy(Order.class));
context.executeSave(order);
3. 高级应用技巧与性能优化
3.1 策略组合模式
当操作流程变得复杂时,可以采用策略组合:
java复制public class CompositeSaveStrategy<T> implements SaveStrategy<T> {
private List<SaveStrategy<T>> strategies = new ArrayList<>();
public void addStrategy(SaveStrategy<T> strategy) {
strategies.add(strategy);
}
@Override
public void executeSave(T entity) {
strategies.forEach(s -> s.executeSave(entity));
}
// 其他方法实现...
}
使用示例:
java复制CompositeSaveStrategy<Order> composite = new CompositeSaveStrategy<>();
composite.addStrategy(new OrderDBSaveStrategy());
composite.addStrategy(new OrderCacheSaveStrategy());
composite.addStrategy(new OrderESSaveStrategy());
3.2 基于注解的策略自动装配
结合Spring等框架可以实现更优雅的策略管理:
java复制@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface StrategyFor {
Class<?> value();
}
@Component
@StrategyFor(Order.class)
public class OrderSaveStrategy implements SaveStrategy<Order> {
// 实现代码...
}
然后通过后处理器自动注册策略:
java复制@Component
public class StrategyRegistry implements ApplicationContextAware {
private Map<Class<?>, SaveStrategy<?>> strategyMap = new ConcurrentHashMap<>();
@Override
public void setApplicationContext(ApplicationContext context) {
Map<String, SaveStrategy> beans = context.getBeansOfType(SaveStrategy.class);
beans.forEach((name, strategy) -> {
StrategyFor annotation = strategy.getClass().getAnnotation(StrategyFor.class);
if(annotation != null) {
strategyMap.put(annotation.value(), strategy);
}
});
}
public SaveStrategy<?> getStrategy(Class<?> entityType) {
return strategyMap.get(entityType);
}
}
3.3 性能优化考量
- 策略对象复用:无状态的策略对象可以设计成单例
- 缓存策略实例:使用缓存减少对象创建开销
- 并行策略执行:对于独立策略可以使用并行流:
java复制strategies.parallelStream().forEach(s -> s.execute(entity));
4. 实战中的坑与解决方案
4.1 策略膨胀问题
当策略类过多时,可以考虑:
- 按功能维度拆分策略接口(如分成SaveStrategy、ValidateStrategy等)
- 使用内部类组织相关策略
- 采用策略模板方法减少重复代码
4.2 上下文数据共享
策略间需要共享数据时,可以:
- 使用ThreadLocal存储上下文
- 设计专门的Context对象传递数据
- 在实体对象中添加临时字段
示例代码:
java复制public class OperationContext<T> {
private Map<String, Object> attributes = new HashMap<>();
public void setAttribute(String key, Object value) {
attributes.put(key, value);
}
public Object getAttribute(String key) {
return attributes.get(key);
}
}
4.3 策略选择逻辑复杂化
当策略选择不再简单基于类型时,可以:
- 引入策略选择器接口:
java复制public interface StrategySelector {
SaveStrategy<?> select(Object condition);
}
- 使用规则引擎(如Drools)管理复杂策略选择
- 实现策略的优先级机制
5. 与其他模式的协作
5.1 策略+工厂方法
java复制public interface SaveStrategyFactory {
SaveStrategy<?> createStrategy(Object condition);
}
public class OrderSaveStrategyFactory implements SaveStrategyFactory {
@Override
public SaveStrategy<?> createStrategy(Object condition) {
if(condition instanceof OrderType) {
switch((OrderType)condition) {
case NORMAL: return new NormalOrderStrategy();
case GROUP: return new GroupOrderStrategy();
case FLASH: return new FlashOrderStrategy();
}
}
return new DefaultOrderStrategy();
}
}
5.2 策略+模板方法
java复制public abstract class AbstractSaveStrategy<T> implements SaveStrategy<T> {
// 模板方法定义流程
public final void save(T entity) {
validate(entity);
preProcess(entity);
executeSave(entity);
postProcess(entity);
}
// 留给子类实现的抽象方法
protected abstract void executeSave(T entity);
// 可选的钩子方法
protected void preProcess(T entity) {
// 默认空实现
}
}
5.3 策略+装饰器模式
java复制public class LoggingSaveStrategyDecorator<T> implements SaveStrategy<T> {
private final SaveStrategy<T> decoratedStrategy;
public LoggingSaveStrategyDecorator(SaveStrategy<T> decorated) {
this.decoratedStrategy = decorated;
}
@Override
public void executeSave(T entity) {
long start = System.currentTimeMillis();
decoratedStrategy.executeSave(entity);
long duration = System.currentTimeMillis() - start;
logger.info("保存操作耗时: {}ms", duration);
}
}
在实际项目中,我通常会先从一个简单的策略模式实现开始,随着业务复杂度的增加逐步引入这些高级技巧。记住,模式是为了让代码更清晰而不是更复杂,当发现模式本身带来了更多复杂度时,可能就是需要重新考虑设计的时候了。