一、原理与实现
1. 定义
-
定义一族算法类,将每个算法分别封装起来,让它们可以互相替换。策略模式可以使算法的变化独立于使用它们的客户端(这里的客户端代指使用算法的代码)。
- 使用策略模式可以将算法的定义与使用隔离开来,保证类的单一职责原则,使得程序整体符合开闭原则。
-
解耦对象
- 工厂模式是解耦对象的创建和使用,
- 观察者模式是解耦观察者和被观察者
- 它解耦的是策略的定义、创建、使用这三部分
2. 策略定义
- 包含一个策略接口和一组实现这个接口的策略类。因为所有的策略类都实现相同的接口,所以,客户端代码基于接口而非实现编程,可以灵活地替换不同的策略。
二、实践
- 结合spring 容器
1. 简单工厂
public interface GenericInterface<E> {
E getType();
}
@Slf4j
public class HandlerFactory<E, T extends GenericInterface<E>> implements InitializingBean, ApplicationContextAware {
private ApplicationContext applicationContext;
/**
* 泛型策略接口类型
*/
private Class<T> strategyInterfaceType;
/**
* java泛型只存在于编译期,无法通过例如T.class的方式在运行时获取其类信息
* 因此利用构造函数传入具体的策略类型class对象为getBeansOfType()方法
* 提供参数
*
* @param strategyInterfaceType 要传入的策略接口类型
*/
public HandlerFactory(Class<T> strategyInterfaceType) {
this.strategyInterfaceType = strategyInterfaceType;
}
/**
* 策略实例容器
*/
private Map<E, T> GET_SHOP_RANK_STRATEGY_MAP;
/**
* 根据不同参数类型获取对应的接口实现类
*
* @param type 参数类型
* @return 参数类型对应的接口实现类
*/
public T getStrategy(E type) {
return GET_SHOP_RANK_STRATEGY_MAP.get(type);
}
@Override
public void afterPropertiesSet() {
Map<String, T> beansOfType = applicationContext.getBeansOfType(strategyInterfaceType);
log.info("afterPropertiesSet beansOfType={}", JsonUtil.dumps(beansOfType));
GET_SHOP_RANK_STRATEGY_MAP = Optional.ofNullable(beansOfType)
.map(beansOfTypeMap -> beansOfTypeMap.values().stream()
.filter(strategy -> StringUtils.isNotEmpty(strategy.getType().toString()))
.collect(Collectors.toMap(strategy -> strategy.getType(), Function.identity())))
.orElse(new HashMap<>(8));
log.info("afterPropertiesSet GET_SHOP_RANK_STRATEGY_MAP={}", JsonUtil.dumps(GET_SHOP_RANK_STRATEGY_MAP) );
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
2. 业务场景
- 一个项目要支持很多游戏, 每个游戏的开始游戏,和结束游戏都是一样的。
- 策略接口
public interface GameCommonStrategyInterface extends GenericInterface<Long> {
/**
* 开始游戏
* @param gameId
* @param userId
* @param lang
* @return
*/
GameStartDTO gameStart(Long gameId, long userId, String lang) ;
/**
* 结束游戏
* @param gameOver
* @param userId
* @param lang
* @return
*/
GameResultDTO gameOver(GameOverDTO gameOver, long userId, String lang);
}
- 策略工厂注册
@Configuration
public class BeanFactoryConfig {
@Bean
public HandlerFactory<Long, GameCommonStrategyInterface> gameCommonStrategyInterface(){
return new HandlerFactory<>(GameCommonStrategyInterface.class);
}
}
- 某一个游戏的具体策略
- type 是一个long 类型的id
@Component
public class SheepGameCommonStrategy implements GameCommonStrategyInterface {
@Override
public GameStartDTO gameStart(Long gameId, long userId, String lang) {
...
}
@Override
public GameResultDTO gameOver(GameOverDTO gameOver, long userId, String lang) {
...
}
@Override
public Long getType() {
return 1L;
}
}
2.1 总结
- 优点
- 将策略接口类型参数化,策略工厂不受接口类型限制,成为任意接口的策略工厂。
网友评论