一、定义
策略模式,针对每一个不同的类型,调用具有共同接口的不同实现类,从而使得它们可以相互替换。
策略模式 ,针对实现同一接口的不同的类,采用不同的策略。比如,面对高级会员、初级会员会采用不同的折扣。
策略模式,可以避免大量的if和else。
二、角色
策略模式涉及到三个角色:
● 环境(Context)角色:调用策略
● 抽象策略(Strategy)角色:抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
● 具体策略(ConcreteStrategy)角色:实现抽象策略接口,包装了相关的算法或行为。
三、代码示例
type 枚举
public enum TypeEnum {
/**
* 类型一
*/
FIRST_TYPE(1, "类型一"),
/**
* 类型二
*/
SECOND_TYPE(2, "类型二"),
/**
* 类型三
*/
THIRD_TYPE(3, "类型三"),
;
/**
* 类型
*/
private final Integer type;
private final String typeName;
TypeEnum(Integer type, String text) {
this.type = type;
this.typeName = text;
}
public Integer getType() {
return type;
}
public String getTypeName() {
return typeName;
}
/**
* 根据 type 获取枚举
*
* @param type
* @return
*/
public static TypeEnum getByType(Integer type) {
for (TypeEnum typeEnum : TypeEnum.values()) {
if (typeEnum.getType().equals(type)) {
return typeEnum;
}
}
return null;
}
public static TypeEnum getByName(String name) {
for (TypeEnum typeEnum : TypeEnum.values()) {
if (typeEnum.getTypeName().equals(name)) {
return typeEnum;
}
}
return null;
}
}
基础类:
/**
* 基础类,写不同策略的公共的代码,避免代码重复
*/
@Service
public class TypeStrategyBaseService {
/**
* 公共代码,避免重复
*/
public void doCommon() {
System.out.println("execute common method.");
}
}
策略模式接口:
/**
* 策略模式接口
*
*/
public interface TypeStrategy {
/**
* 做某事
* @param param
* @return
*/
String doSth(String param) ;
/**
* 获取类型
* @return
*/
Integer getType();
}
第一种策略:
/**
* 第一种策略
*/
@Service
public class FirstTypeStrategyServerImpl extends TypeStrategyBaseService implements TypeStrategy {
/**
* 业务逻辑
*/
@Override
public String doSth(String param) {
doCommon();
return "FirstStrategy doSth " + param;
}
@Override
public Integer getType() {
return TypeEnum.FIRST_TYPE.getType();
}
}
第二种策略:
/**
* 第二种策略
*/
@Service
public class SecondTypeStrategyServiceImpl extends TypeStrategyBaseService implements TypeStrategy {
/**
* 业务逻辑
*/
@Override
public String doSth(String param) {
doCommon();
return "SecondStrategy doSth " + param;
}
@Override
public Integer getType() {
return TypeEnum.SECOND_TYPE.getType();
}
}
配置 策略对应的 map:
@Component
public class SpringApplicationContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext ctx) throws BeansException {
applicationContext = ctx;
}
/**
* 获取类型为 key,策略作为value 的 map
*
*/
public static <T> Map<String, T> getBeansOfType(Class<T> classType) {
if (applicationContext == null) {
log.warn("ApplicationContext is null.classType:{}", JSON.toJSONString(classType));
throw new IllegalStateException("getBeansOfType failed.ApplicationContext is null");
}
return applicationContext.getBeansOfType(classType);
}
}
策略 Context
/**
* 策略 Context,获取策略
*/
@Component
public class TypeStrategyContext {
/**
* 存在多个容器的时候会被加载多次
*/
private static volatile Map<Integer, TypeStrategy> strategyMap;
@PostConstruct
public static void init() {
if (strategyMap == null) {
Map<String, TypeStrategy> subBeanMap = SpringApplicationContextHolder.getBeansOfType(TypeStrategy.class);
strategyMap = subBeanMap.values().stream().collect(Collectors.toMap(TypeStrategy::getType, typeStrategy -> typeStrategy));
}
}
/**
* 根据 type 获取不同的策略,再执行业务逻辑。
*/
public static TypeStrategy getStrategyByType(int type) {
return strategyMap.get(type);
}
}
调用策略的类:
/**
* 调用类
*
*/
@Service
public class TypeStrategyClientService {
/**
* 根据 type 获取不同的策略,再执行业务逻辑。
*/
public String doSthByType(Integer type, String param) {
TypeStrategy typeStrategy = TypeStrategyContext.getStrategyByType(type);
if (typeStrategy == null) {
throw new IllegalStateException("类型"+ type + "不存在策略");
}
return typeStrategy.doSth(param);
}
}
测试:
@Test
public void testDoSthByType2() {
String result = typeStrategyClientService.doSthByType(1, "12345");
System.out.println("==============> typeStrategyClientService result: " + result);
}
输出结果:
type 为1时,结果为:
execute common method.
==============> result: FirstStrategy doSth 12345
type为2时,结果为:
execute common method.
==============> result: SecondStrategy doSth 12345