源码
定义
定义了一些平行的算法组,分别封装起来,算法之间可以相互替换,此模式使算法的变化独立于调用者之外
算法结构
- 抽象策略角色(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);
int typeId();
}
/**
* 夏季购车节
*/
@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;
}
@Override
public int typeId() {
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;
}
@Override
public int typeId() {
return 2;
}
}
package com.shawntime.designpattern.strategy.example;
import java.util.HashMap;
import java.util.Map;
import org.junit.Assert;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
/**
* 礼品信息环境角色类
*/
@Component
public class GiftInfoContext implements ApplicationListener<ContextRefreshedEvent> {
/**
* 注入的策略
*/
private Map<Integer, IGiftInfoStrategyService> giftInfoStrategyServiceMap = new HashMap<>();
/**
* 对外暴露的统一获取礼品信息的返回
*/
public GiftInfo getGiftInfo(int typeId, int activityId) {
IGiftInfoStrategyService giftInfoStrategyService = giftInfoStrategyServiceMap.get(typeId);
Assert.assertNotNull(giftInfoStrategyService);
return giftInfoStrategyService.getGiftInfo(activityId);
}
public Map<Integer, IGiftInfoStrategyService> getGiftInfoStrategyServiceMap() {
return giftInfoStrategyServiceMap;
}
public void setGiftInfoStrategyServiceMap(Map<Integer, IGiftInfoStrategyService> giftInfoStrategyServiceMap) {
this.giftInfoStrategyServiceMap = giftInfoStrategyServiceMap;
}
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
ApplicationContext applicationContext = contextRefreshedEvent.getApplicationContext();
if (applicationContext.getParent() == null) {
Map<String, IGiftInfoStrategyService> infoStrategyServiceMap =
applicationContext.getBeansOfType(IGiftInfoStrategyService.class);
infoStrategyServiceMap.values()
.forEach(strategyService -> {
int typeId = strategyService.typeId();
giftInfoStrategyServiceMap.put(typeId, strategyService);
});
}
}
}
/**
* 礼品信息配置类
*/
@ComponentScan("com.shawntime.designpattern.strategy.example")
@Configuration
public class GiftInfoConfig {
}
/**
* 礼品信息调用
*/
public class GiftInfoTest {
private AnnotationConfigWebApplicationContext context;
@Before
public void before() {
context = new AnnotationConfigWebApplicationContext();
context.register(GiftInfoConfig.class);
context.refresh();
}
@Test
public void getGiftInfo() {
GiftInfoContext giftInfoContext = context.getBean(GiftInfoContext.class);
GiftInfo giftInfo = giftInfoContext.getGiftInfo(1, 2);
Assert.assertNotNull(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);
}
}