源碼
定義
定義了一些平行的算法組,分別封裝起來,算法之間可以相互替換,此模式使算法的變化獨(dú)立于調(diào)用者之外
算法結(jié)構(gòu)
- 抽象策略角色(Strategy):這是一個(gè)抽象類或者接口,將算法的行為進(jìn)行封裝,所有的策略類都要實(shí)現(xiàn)該接口
- 具體策略角色(ConcreteStrategy):封裝了具體的算法和行為
- 環(huán)境角色(Context):持有一個(gè)抽象策略的引用,并提供統(tǒng)一調(diào)用的入口
結(jié)構(gòu)代碼
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相關(guān)業(yè)務(wù)
}
}
package com.shawntime.designpattern.strategy.demo;
/**
* Created by shma on 2018/9/26.
*/
public class ConcreteStrategyB implements Strategy {
public void strategyInterface() {
// B相關(guān)業(yè)務(wù)
}
}
package com.shawntime.designpattern.strategy.demo;
/**
* 環(huán)境角色類
*/
public class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
// 對(duì)外暴露的策略方法
public void contextInterface() {
strategy.strategyInterface();
}
public Strategy getStrategy() {
return strategy;
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
}
項(xiàng)目實(shí)例
背景
在項(xiàng)目中,根據(jù)專題id去獲得該專題下活動(dòng)的禮品信息, 由于每個(gè)類型活動(dòng)禮品的方式不同,相互之間沒有關(guān)聯(lián),屬于平級(jí)的行為,因而采用策略模式。
方案1:通過spring配置注入策略
public interface IGiftInfoStrategyService {
GiftInfo getGiftInfo(int activityId);
int typeId();
}
/**
* 夏季購車節(jié)
*/
@Service
public class SummerBuyDayGiftInfoStrategyService implements IGiftInfoStrategyService {
@Resource
private GiftInfoMapper giftInfoMapper;
public GiftInfo getGiftInfo(int activityId) {
// 從數(shù)據(jù)庫中查詢
GiftInfo giftInfo = new GiftInfo();
giftInfo.setGiftId(1);
giftInfo.setGiftName("鐵鍋三件套");
giftInfoMapper.getGiftInfoByActivityId(activityId)
return giftInfo;
}
@Override
public int typeId() {
return 1;
}
}
/**
* 雙11活動(dòng)
*/
@Service
public class DoubleElevenGiftInfoStrategyService implements IGiftInfoStrategyService {
@Override
public GiftInfo getGiftInfo(int activityId) {
// 雙11調(diào)用統(tǒng)一平臺(tái)接口獲取禮品信息
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;
/**
* 禮品信息環(huán)境角色類
*/
@Component
public class GiftInfoContext implements ApplicationListener<ContextRefreshedEvent> {
/**
* 注入的策略
*/
private Map<Integer, IGiftInfoStrategyService> giftInfoStrategyServiceMap = new HashMap<>();
/**
* 對(duì)外暴露的統(tǒng)一獲取禮品信息的返回
*/
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 {
}
/**
* 禮品信息調(diào)用
*/
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:通過靜態(tài)方法配置
public interface IGiftInfoStrategyService {
GiftInfo getGiftInfo(int activityId);
}
/**
* 雙11活動(dòng)
*/
@Service
public class DoubleElevenGiftInfoStrategyService implements IGiftInfoStrategyService {
// 靜態(tài)代碼塊中注冊(cè)關(guān)聯(lián)
static {
GiftInfoContext.registerProvider(2, DoubleElevenGiftInfoStrategyService.class);
}
@Override
public GiftInfo getGiftInfo(int activityId) {
// 雙11調(diào)用統(tǒng)一平臺(tái)接口獲取禮品信息
GiftInfo giftInfo = new GiftInfo();
giftInfo.setGiftId(902);
giftInfo.setGiftName("空氣凈化器");
return giftInfo;
}
}
/**
* 夏季購車節(jié)
*/
@Service
public class SummerBuyDayGiftInfoStrategyService implements IGiftInfoStrategyService {
// 靜態(tài)代碼塊中注冊(cè)關(guān)聯(lián)
static {
GiftInfoContext.registerProvider(1, SummerBuyDayGiftInfoStrategyService.class);
}
@Resource
private GiftInfoMapper giftInfoMapper;
public GiftInfo getGiftInfo(int activityId) {
// 從數(shù)據(jù)庫中查詢
GiftInfo giftInfo = new GiftInfo();
giftInfo.setGiftId(1);
giftInfo.setGiftName("鐵鍋三件套");
giftInfoMapper.getGiftInfoByActivityId(activityId)
return giftInfo;
}
}
/**
* 禮品信息環(huán)境角色類
*/
@Component
public class GiftInfoContext {
private static final Logger logger = LoggerFactory.getLogger(GiftInfoContext.class);
// 策略映射map
private static final Map<Integer, Class<?>> providers = new HashMap<>();
// 提供給策略具體實(shí)現(xiàn)類的注冊(cè)返回
public static void registerProvider(int subjectId, Class<?> provider) {
providers.put(subjectId, provider);
}
// 對(duì)外暴露的獲取禮品信息接口返回
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自動(dòng)注入list、map
對(duì)于@Resource聲明的數(shù)組、集合類型,spring并不是根據(jù)beanName去找容器中對(duì)應(yīng)的bean,而是把容器中所有類型與集合(數(shù)組)中元素類型相同的bean構(gòu)造出一個(gè)對(duì)應(yīng)集合,注入到目標(biāo)bean中
public interface IGiftInfoStrategyService {
GiftInfo getGiftInfo(int activityId);
getTypeId();
}
/**
* 夏季購車節(jié)
*/
@Service
public class SummerBuyDayGiftInfoStrategyService implements IGiftInfoStrategyService {
@Resource
private GiftInfoMapper giftInfoMapper;
public GiftInfo getGiftInfo(int activityId) {
// 從數(shù)據(jù)庫中查詢
GiftInfo giftInfo = new GiftInfo();
giftInfo.setGiftId(1);
giftInfo.setGiftName("鐵鍋三件套");
giftInfoMapper.getGiftInfoByActivityId(activityId)
return giftInfo;
}
public int getTypeId() {
return 1;
}
}
/**
* 雙11活動(dòng)
*/
@Service
public class DoubleElevenGiftInfoStrategyService implements IGiftInfoStrategyService {
@Override
public GiftInfo getGiftInfo(int activityId) {
// 雙11調(diào)用統(tǒng)一平臺(tái)接口獲取禮品信息
GiftInfo giftInfo = new GiftInfo();
giftInfo.setGiftId(902);
giftInfo.setGiftName("空氣凈化器");
return giftInfo;
}
public int getTypeId() {
return 2;
}
}
/**
* 禮品信息環(huán)境角色類
*/
@Component
public class GiftInfoContext {
// Spring自動(dòng)注入
@Resource
private List<IGiftInfoStrategyService> giftInfoStrategyServiceList;
// 對(duì)外暴露的統(tǒng)一獲取禮品信息的返回
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);
}
}