Spring优雅的实现策略模式
2018-09-26 本文已影响103人
传达室马大爷
源码
定义
定义了一些平行的算法组,分别封装起来,算法之间可以相互替换,此模式使算法的变化独立于调用者之外
算法结构
- 抽象策略角色(Strategy):这是一个抽象类或者接口,将算法的行为进行封装,所有的策略类都要实现该接口
- 具体策略角色(ConcreteStrategy):封装了具体的算法和行为
- 环境角色(Context):持有一个抽象策略的引用,并提供统一调用的入口
结构代码
package com.shawntime.designpattern.strategy.demo;
/**
* 抽象策略类
*/
public interface Strategy {
// 策略方法
void strategyInterface();
}
package com.shawntime.designpattern.strategy.demo;
/**
* Created by shma on 2018/9/26.
*/
public class ConcreteStrategyA implements Strategy {
public void strategyInterface() {
// A相关业务
}
}
package com.shawntime.designpattern.strategy.demo;
/**
* Created by shma on 2018/9/26.
*/
public class ConcreteStrategyB implements Strategy {
public void strategyInterface() {
// B相关业务
}
}
package com.shawntime.designpattern.strategy.demo;
/**
* 环境角色类
*/
public class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
// 对外暴露的策略方法
public void contextInterface() {
strategy.strategyInterface();
}
public Strategy getStrategy() {
return strategy;
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
}
项目实例
背景
在项目中,根据专题id去获得该专题下活动的礼品信息, 由于每个专题活动礼品的方式不同,相互之间没有关联,属于平级的行为,因而采用策略模式。
方案1:通过spring配置注入策略
public interface IGiftInfoStrategyService {
GiftInfo getGiftInfo(int activityId);
}
/**
* 夏季购车节
*/
@Service
public class SummerBuyDayGiftInfoStrategyService implements IGiftInfoStrategyService {
@Resource
private GiftInfoMapper giftInfoMapper;
public GiftInfo getGiftInfo(int activityId) {
// 从数据库中查询
GiftInfo giftInfo = new GiftInfo();
giftInfo.setGiftId(1);
giftInfo.setGiftName("铁锅三件套");
giftInfoMapper.getGiftInfoByActivityId(activityId)
return giftInfo;
}
}
/**
* 双11活动
*/
@Service
public class DoubleElevenGiftInfoStrategyService implements IGiftInfoStrategyService {
@Override
public GiftInfo getGiftInfo(int activityId) {
// 双11调用统一平台接口获取礼品信息
GiftInfo giftInfo = new GiftInfo();
giftInfo.setGiftId(902);
giftInfo.setGiftName("空气净化器");
return giftInfo;
}
}
/**
* 礼品信息环境角色类
*/
@Component
public class GiftInfoContext {
// 注入的策略
@Autowired
private Map<Integer, IGiftInfoStrategyService> giftInfoStrategyServiceMap;
// 对外暴露的统一获取礼品信息的返回
public GiftInfo getGiftInfo(int subjectId, int activityId) {
IGiftInfoStrategyService giftInfoStrategyService = giftInfoStrategyServiceMap.get(subjectId);
Assert.assertNotNull(giftInfoStrategyService);
return giftInfoStrategyService.getGiftInfo(activityId);
}
}
/**
* 礼品信息配置类
*/
@Configuration
public class GiftInfoConfig {
@Resource
private IGiftInfoStrategyService doubleElevenGiftInfoStrategyService;
@Resource
private IGiftInfoStrategyService summerBuyDayGiftInfoStrategyService;
/**
* 注入bean
*/
@Bean
public Map<Integer, IGiftInfoStrategyService> giftInfoStrategyServiceMap() {
Map<Integer, IGiftInfoStrategyService> dataMap = new HashMap<>();
dataMap.put(1, summerBuyDayGiftInfoStrategyService);
dataMap.put(2, doubleElevenGiftInfoStrategyService);
return dataMap;
}
}
/**
* 礼品信息调用
*/
public class GiftInfoTest {
@Resource
private GiftInfoContext giftInfoContext;
public GiftInfo getGiftInfo(int subjectId, int activityId) {
GiftInfo giftInfo = giftInfoContext.getGiftInfo(subjectId, activityId);
Assert.assertNotNull(giftInfo);
return giftInfo;
}
}
方案2:通过静态方法配置
public interface IGiftInfoStrategyService {
GiftInfo getGiftInfo(int activityId);
}
/**
* 双11活动
*/
@Service
public class DoubleElevenGiftInfoStrategyService implements IGiftInfoStrategyService {
// 静态代码块中注册关联
static {
GiftInfoContext.registerProvider(2, DoubleElevenGiftInfoStrategyService.class);
}
@Override
public GiftInfo getGiftInfo(int activityId) {
// 双11调用统一平台接口获取礼品信息
GiftInfo giftInfo = new GiftInfo();
giftInfo.setGiftId(902);
giftInfo.setGiftName("空气净化器");
return giftInfo;
}
}
/**
* 夏季购车节
*/
@Service
public class SummerBuyDayGiftInfoStrategyService implements IGiftInfoStrategyService {
// 静态代码块中注册关联
static {
GiftInfoContext.registerProvider(1, SummerBuyDayGiftInfoStrategyService.class);
}
@Resource
private GiftInfoMapper giftInfoMapper;
public GiftInfo getGiftInfo(int activityId) {
// 从数据库中查询
GiftInfo giftInfo = new GiftInfo();
giftInfo.setGiftId(1);
giftInfo.setGiftName("铁锅三件套");
giftInfoMapper.getGiftInfoByActivityId(activityId)
return giftInfo;
}
}
/**
* 礼品信息环境角色类
*/
@Component
public class GiftInfoContext {
private static final Logger logger = LoggerFactory.getLogger(GiftInfoContext.class);
// 策略映射map
private static final Map<Integer, Class<?>> providers = new HashMap<>();
// 提供给策略具体实现类的注册返回
public static void registerProvider(int subjectId, Class<?> provider) {
providers.put(subjectId, provider);
}
// 对外暴露的获取礼品信息接口返回
public static GiftInfo getGiftInfo(int subjectId, int activityId) {
Class<?> providerClazz = providers.get(subjectId);
Assert.assertNotNull(providerClazz);
Object bean = SpringUtils.getBean(providerClazz);
Assert.assertNotNull(bean);
if (bean instanceof IGiftInfoStrategyService) {
IGiftInfoStrategyService strategyService = (IGiftInfoStrategyService) bean;
return strategyService.getGiftInfo(activityId);
}
logger.error("Not Class with IGiftInfoListService: {}", providerClazz.getName());
return null;
}
}
public class GiftInfoTest {
public GiftInfo getGiftInfo(int subjectId, int activityId) {
GiftInfo giftInfo = GiftInfoContext.getGiftInfo(subjectId, activityId);
Assert.assertNotNull(giftInfo);
return giftInfo;
}
}
方案3:通过spring自动注入list、map
对于@Resource声明的数组、集合类型,spring并不是根据beanName去找容器中对应的bean,而是把容器中所有类型与集合(数组)中元素类型相同的bean构造出一个对应集合,注入到目标bean中
public interface IGiftInfoStrategyService {
GiftInfo getGiftInfo(int activityId);
getTypeId();
}
/**
* 夏季购车节
*/
@Service
public class SummerBuyDayGiftInfoStrategyService implements IGiftInfoStrategyService {
@Resource
private GiftInfoMapper giftInfoMapper;
public GiftInfo getGiftInfo(int activityId) {
// 从数据库中查询
GiftInfo giftInfo = new GiftInfo();
giftInfo.setGiftId(1);
giftInfo.setGiftName("铁锅三件套");
giftInfoMapper.getGiftInfoByActivityId(activityId)
return giftInfo;
}
public int getTypeId() {
return 1;
}
}
/**
* 双11活动
*/
@Service
public class DoubleElevenGiftInfoStrategyService implements IGiftInfoStrategyService {
@Override
public GiftInfo getGiftInfo(int activityId) {
// 双11调用统一平台接口获取礼品信息
GiftInfo giftInfo = new GiftInfo();
giftInfo.setGiftId(902);
giftInfo.setGiftName("空气净化器");
return giftInfo;
}
public int getTypeId() {
return 2;
}
}
/**
* 礼品信息环境角色类
*/
@Component
public class GiftInfoContext {
// Spring自动注入
@Resource
private List<IGiftInfoStrategyService> giftInfoStrategyServiceList;
// 对外暴露的统一获取礼品信息的返回
public GiftInfo getGiftInfo(int subjectId, int activityId) {
Optional<IGiftInfoStrategyService> optional = giftInfoStrategyServiceList.stream()
.filter(service -> service.getTypeId = subjectId)
.findFrist();
if (!optional.isPresent()) {
Assert.assertNotNull(giftInfoStrategyService);
}
return optional.get().getGiftInfo(activityId);
}
}
/**
* 礼品信息配置类
*/
@Configuration
public class GiftInfoConfig {
@Resource
private IGiftInfoStrategyService doubleElevenGiftInfoStrategyService;
@Resource
private IGiftInfoStrategyService summerBuyDayGiftInfoStrategyService;
/**
* 注入bean
*/
@Bean
public Map<Integer, IGiftInfoStrategyService> giftInfoStrategyServiceMap() {
Map<Integer, IGiftInfoStrategyService> dataMap = new HashMap<>();
dataMap.put(1, summerBuyDayGiftInfoStrategyService);
dataMap.put(2, doubleElevenGiftInfoStrategyService);
return dataMap;
}
}
/**
* 礼品信息调用
*/
public class GiftInfoTest {
@Resource
private GiftInfoContext giftInfoContext;
public GiftInfo getGiftInfo(int subjectId, int activityId) {
GiftInfo giftInfo = giftInfoContext.getGiftInfo(subjectId, activityId);
Assert.assertNotNull(giftInfo);
return giftInfo;
}
}