前言
最近在工作中偶遇一个看似平平无奇的需求,简单概括就是改造项目里之前做的PDF导出模板和数据,这里需要根据不同状态导出不同的模板数据。接到需求那一刻,脑海里瞬间就有了解决方案,只需要简单修改一下模板,然后修改查询回填数据就可以了嘛 so easy ~ 。当我找到这一块的代码的时候整个人都懵了,因为需要判断两个状态,之前的代码是这样实现的:switch…case… 接着里边再用上祖传的 if…else… 判断,注释寥寥几行展示了前人强大的脑回路和过硬的代码功底。尽管有提取方法,代码也没有显得很臃肿,不过俄罗斯套娃式写法也是换汤不换药,代码的可读性可维护性真是极差。人家是前人栽树,后人乘凉,到我这变成前人挖坑,后人填坑。思来想去记得之前有看过一篇技术文章介绍了如何避免大量if判断,接着就抓紧去研究了一番,想到我的博客已经杂草丛生了,就在这里作个记录吧。
一、什么是策略模式
专业回答: 策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。(该模式定义了一系列算法,并将每个算法封装隔离起来,使它们可以相互替换,且算法的变化不会影响算法的使用
)
业余回答:假设策略模式的实现就好比一场线上模拟篮球比赛,需要进攻、需要防守,身为全局掌控者的你要靠制定各种各样的战术来赢得比赛,这些战术就是你的策略,在球场攻防转换的过程中,进攻和防守这些策略之间是相互隔离开的,进攻的时候不需要防守,防守的时候不需要进攻。所以在代码层面的实现就显而易见了,通过定义一个执行入口(接口),不同的策略类分别实现这个接口,要用哪个就调那个就可以
。
二、策略模式的优缺点
优点:
- 避免使用多重条件判断,提高系统可维护性;
- 算法可以自由切换;
- 扩展性好,可以在不修改原算法的基础上,灵活增加新的算法;
- 恰当使用继承可以把公共的代码转移到父类里面,提高代码复用性;
缺点:
- 如果需要增加策略,只能新增策略类;
- 使用者必须理解所有策略算法的区别,以便适时选择恰当的算法类;
三、代码示例
1、简单实现便于理解:
- 定义策略入口
/**
* @author: Marlon
* @date: 2022/8/28
**/
public interface Strategy {
String strategyHandler();
}
- 定义具体策略实现
/**
* @author: Marlon
* @date: 2022/8/28
**/
public class OffenseStrategy implements Strategy{
@Override
public String strategyHandler() {
return "This is offense ...";
}
}
/**
* @author: Marlon
* @date: 2022/8/28
**/
public class DefendStrategy implements Strategy {
@Override
public String strategyHandler() {
return "This is defend ...";
}
}
- 使用 Context 来查看当它改变策略 Strategy 时的行为变化。
/**
* @author: Marlon
* @date: 2022/8/28
**/
public class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public String executeStrategy() {
return strategy.strategyHandler();
}
}
- 测试
/**
* @author: Marlon
* @date: 2022/8/28
**/
public class Test {
public static void main(String[] args) {
DefendStrategy defendStrategy = new DefendStrategy();
OffenseStrategy offenseStrategy = new OffenseStrategy();
//执行策略
Context context = new Context(defendStrategy);
System.out.println(context.executeStrategy());
//执行策略
context = new Context(offenseStrategy);
System.out.println(context.executeStrategy());
}
/**
* 输出结果:
*
* This is defend ...
* This is offense ...
*
**/
}
2、使用工厂模式+策略模式
- 定义策略入口
/**
* @author: Marlon
* @date: 2022/8/28
**/
public interface Strategy {
String strategyHandler();
}
- 定义具体策略实现
/**
* @author: Marlon
* @date: 2022/8/28
**/
public class OffenseStrategy implements Strategy{
@Override
public String strategyHandler() {
return "This is offense ...";
}
}
/**
* @author: Marlon
* @date: 2022/8/28
**/
public class DefendStrategy implements Strategy {
@Override
public String strategyHandler() {
return "This is defend ...";
}
}
- 枚举定义映射地址
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;
/**
* @author: Marlon
* @date: 2022/8/28
**/
@Getter
@AllArgsConstructor
@NoArgsConstructor
public enum StrategyEnum {
/**
* offense
*/
OFFENSE("offense", "com.marlon.OffenseStrategy"),
/**
* defend
*/
DEFEND("defend", "com.marlon.DefendStrategy");
private String code;
private String className;
public static String getClassNameByCode(final String code) {
String className = "";
if (StringUtils.isEmpty(code)) {
return className;
}
for (StrategyEnum se : StrategyEnum.values()) {
if (se.code.equalsIgnoreCase(code)) {
className = se.getClassName();
break;
}
}
return className;
}
}
- 工厂类反射执行
/**
* @author: Marlon
* @date: 2022/8/28
**/
public class StrategyFactory {
/**
* 使用策略工厂获取具体策略实现
*
* @param code 策略编码
* @return 策略接口
*/
public static Strategy getStrategy(final String code) {
try {
return (Strategy) Class.forName(StrategyEnum.getClassNameByCode(code)).newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
}
- 上下文获取具体策略
import java.util.Objects;
/**
* @author: Marlon
* @date: 2022/8/28
**/
public class ContextStrategy {
public static String strategyHandler(final String code){
if(StringUtils.isEmpty(code)){
return "code is not null...";
}
Strategy strategy = StrategyFactory.getStrategy(code);
if(Objects.isNull(strategy))
{
return "strategy is null...";
}
return strategy.strategyHandler();
}
}
- 测试
public static void main(String[] args) {
//执行DEFEND策略
System.out.println(ContextStrategy.strategyHandler(StrategyEnum.DEFEND.getCode()));
//执行OFFENSE策略
System.out.println(ContextStrategy.strategyHandler(StrategyEnum.OFFENSE.getCode()));
}
/**
* 输出结果:
*
* This is defend ...
* This is offense ...
*
**/
2、使用策略模式+模板模式
- 定义策略入口
/**
* @author: Marlon
* @date: 2022/8/28
**/
public interface Strategy {
String getStrategy();
String strategyHandler();
String abstractFetchHandler();
}
- 定义模板抽象类
/**
* @author: Marlon
* @date: 2022/8/28
**/
public abstract class AbstractFetchStrategy implements Strategy {
public abstract String strategyHandler();
@Override
public final String abstractFetchHandler() {
String publicMethod = "This is public method";
String strategy = this.strategyHandler();
return publicMethod + strategy;
}
}
- 定义具体策略实现
import org.springframework.stereotype.Component;
/**
* @author: Marlon
* @date: 2022/8/28
**/
@Component
public class DefendStrategy extends AbstractFetchStrategy implements Strategy {
@Override
public String getStrategy() {
return StrategyEnum.DEFEND.getCode();
}
@Override
public String strategyHandler() {
return "This is defend ...";
}
}
import org.springframework.stereotype.Component;
/**
* @author: Marlon
* @date: 2022/8/28
**/
@Component
public class OffenseStrategy extends AbstractFetchStrategy implements Strategy {
@Override
public String getStrategy() {
return StrategyEnum.OFFENSE.getCode();
}
@Override
public String strategyHandler() {
return "This is offense ...";
}
}
- 枚举定义
/**
* @author: Marlon
* @date: 2022/8/28
**/
@Getter
@AllArgsConstructor
@NoArgsConstructor
public enum StrategyEnum {
/**
* offense
*/
OFFENSE("offense"),
/**
* defend
*/
DEFEND("defend");
private String code;
}
- 上下文获取具体策略
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author: Marlon
* @date: 2022/8/28
*
* 实现ApplicationContextAware 这个类就可以方便获得ApplicationContext中的所有bean。
* 换句话说,就是这个类可以直接获取spring配置文件中,所有有引用到的bean对象。
**/
@Component
public class ContextStrategy implements ApplicationContextAware {
private static final Map<String, Strategy> context = new ConcurrentHashMap<>();
/**
* 通过枚举获取对应的bean
* @param strategyEnum 策略编码
* @return bean
*/
public static Strategy getByStrategy(final StrategyEnum strategyEnum) {
return context.get(strategyEnum.getCode());
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
//获取Strategy接口所有实现类 并放入ConcurrentHashMap
Map<String, Strategy> strategyMap = applicationContext.getBeansOfType(Strategy.class);
strategyMap.forEach((code,strategy)->{
context.put(strategy.getStrategy(),strategy);
});
}
}
- 调用 注意:此调用需要在spring环境使用
Strategy defendStrategy = ContextStrategy.getByStrategy(StrategyEnum.DEFEND);
System.out.println(defendStrategy.abstractFetchHandler());
Strategy offenseStrategy = ContextStrategy.getByStrategy(StrategyEnum.OFFENSE);
System.out.println(offenseStrategy.abstractFetchHandler());
/**
* 输出结果:
*
* This is defend ...
* This is offense ...
*
**/
![](https://i-blog.csdnimg.cn/blog_migrate/459a056166111e7c57bb3f1792b7199f.webp?x-image-process=image/format,png#pic_center)
文章仅用作记录分享,若有不当,还望指正。
最近开通个人了微信公众号,以后将会定期分享工作学习过程中遇到的问题,欢迎关注与我一道成长交流~:
微信搜索: MYY668999
或 程序猿爱篮球
即可上车。