设计模式之策略模式
一 介绍
策略模式(Strategy Pattern)
是指定义了算法家族、分别封装起来,让它们之间可以互相替换,此模式让算法的变化不会影响到使用算法的用户
策略模式的应用场景
1、假如系统中有很多类,而他们的区别仅仅在于他们的行为不同。
2、一个系统需要动态地在几种算法中选择一种
优点:
1、策略模式符合开闭原则。
2、避免使用多重条件转移语句,如if…else…语句、switch语句
3、使用策略模式可以提高算法的保密性和安全性
缺点:
1、客户端必须知道所有的策略,并且自行决定使用哪一个策略类。
2、代码中会产生非常多策略类,增加维护难度
二 实战例子
类图
业务需求:一个表作为字典表,type作为大类分类标志,fieldType作为小类的分类标志
2.1 写一个工厂绑定type与对象
@Component
public class SecurityFactory {
private static ConcurrentHashMap<Integer, SecurityStrategyService> map = new ConcurrentHashMap<>();
//存入
public void setSecurityConfig(Integer type,SecurityStrategyService service){
map.putIfAbsent(type,service);
}
//取出
public SecurityStrategyService getSecurityConfig(Integer type){
return map.get(type);
}
}
2.2 定义父类接口 和 抽象类
核心:在interface和实现类之间隔一层抽象类abstract,方便放一些公共的方法
public interface SecurityStrategyService {
//校验参数是否在枚举内
void validParam(List<Integer> fieldTypeList);
}
public abstract class AbstractSecurityStrategy implements SecurityStrategyService{
}
2.3 3个实现类
@Service
public class AuthCategoryStrategyImpl extends AbstractSecurityStrategy implements InitializingBean {
@Resource
private SecurityFactory securityFactory;
@Override
public void validParam(List<Integer> fieldTypeList) {
//todo 校验认证种类参数
System.out.println("校验认证种类参数");
}
@Override
public void afterPropertiesSet() throws Exception {
securityFactory.setSecurityConfig(SecurityTypeEnum.AUTH_TYPE.getCode(),this);
}
}
@Service
public class AuthSecurityStrategyImpl extends AbstractSecurityStrategy implements InitializingBean {
@Resource
private SecurityFactory securityFactory;
@Override
public void validParam(List<Integer> fieldTypeList) {
//todo 校验认证安全参数
System.out.println("校验认证安全参数");
}
@Override
public void afterPropertiesSet() throws Exception {
securityFactory.setSecurityConfig(SecurityTypeEnum.AUTH_SECURITY.getCode(),this);
}
}
@Service
public class SystemManageStrategyImpl extends AbstractSecurityStrategy implements InitializingBean {
@Resource
private SecurityFactory securityFactory;
@Override
public void validParam(List<Integer> fieldTypeList) {
//todo 校验系统管理参数
System.out.println("校验系统管理参数");
}
@Override
public void afterPropertiesSet() throws Exception {
securityFactory.setSecurityConfig(SecurityTypeEnum.SYSTEM_MANAGE.getCode(),this);
}
}
2.4 动作执行类
//用这个类隔开业务方与策略模式,它成了区别工厂模式的标志类
public class SecurityStrategyActivity {
private SecurityStrategyService securityStrategyService;
public SecurityStrategyActivity(SecurityStrategyService securityStrategyService) {
this.securityStrategyService = securityStrategyService;
}
/**
* 校验参数
*/
public void validParam(List<Integer> fieldTypeList){
securityStrategyService.validParam(fieldTypeList);
}
}
2.5 调用(业务类中)
//1.验证传值是否在枚举内--传统写法
Integer type = securityConfig.getType();
List<Integer> fieldTypeList = securityConfig.getFieldType();
if (type == SecurityTypeEnum.AUTH_SECURITY.getCode()) {
fieldTypeList.stream().forEach(item -> {
SecurityConfigEnum inSecurityConfigEnum = SecurityConfigEnum.isInSecurityConfigEnum(item);
AssertUtil.notNull(inSecurityConfigEnum, ComErrorCode.PARAM_VALID_ERROR);
});
} else if (type == SecurityTypeEnum.AUTH_TYPE.getCode()) {
fieldTypeList.stream().forEach(item -> {
AuthCategoryEnum authCategoryEnum = AuthCategoryEnum.isInAuthCategoryEnum(item);
AssertUtil.notNull(authCategoryEnum, ComErrorCode.PARAM_VALID_ERROR);
});
} else if (type == SecurityTypeEnum.SYSTEM_MANAGE.getCode()) {
fieldTypeList.stream().forEach(item -> {
SystemManageEnum systemManageEnum = SystemManageEnum.isInSystemManageEnum(item);
AssertUtil.notNull(systemManageEnum, ComErrorCode.PARAM_VALID_ERROR);
});
} else {
}
//2.验证传值是否在枚举内--使用策略模式的写法
SecurityStrategyActivity securityStrategyActivity = new SecurityStrategyActivity(securityFactory.getSecurityConfig(type));
securityStrategyActivity.validParam(fieldTypeList);
在动作类SecurityStrategyActivity 可以写很多方法,比如对象组装等,这样就完成了策略模式