1.概述
本篇文章主要介绍策略模式在SpringBoot框架中如何使用。是一篇策略模式的应用实践的文章,需要对设计模式的理论又一定的了解。
1.1 策略模式简述
策略模式包含以下3个核心角色:
- 环境(Context):定义了使用算法的环境,负责将客户端请求委派给具体的策略对象执行。环境类可以通过依赖注入、简单工厂等方式来获取具体策略对象。
- 抽象策略(Abstract Strategy):定义了策略对象的公共接口或抽象类,规定了具体策略类必须实现的方法。
- 具体策略(Concrete Strategy):实现了抽象策略定义的接口或抽象类,包含了具体的算法实现。
2.实现
作为程序员,无论是在日常开发、学习中,肯定会学习了解各种的设计模式。在开发中我们如果根据需求选择合适的设计模式,使得我们写出的代码更加优雅,且具被拓展性,可读性,是需要我们时刻思考的。
收到项目现场转来的一个紧急需求,需要解析一批csv格式的文件入库,每个csv文件都对应一套数据,后续跟能还会增加新的数据。看到之前的代码就是一阵无语…,一坨 “if-else” 堆砌代码。
2.1构建思路
根据上面的需求不同类型数据文件采用不同的处理方法,对于有经验的程序员,肯定第一个想到的肯定是策略模式。若对设计模式不是很熟,也可根据需求对照设计模式定义挑选。
- 定义可识别常量:这里根据不同的文件名标识策略类型,使用文件名调用对应的策略实例。
- 定义策略接口:每个文件定义一种解析实现,实现对应的解析逻辑,并提取抽接口,定义为对外统一访问入口。
- Context设计:通过Map来存储策略定义数据,调用者调用是通过策略标识来获取对应策略实例。
在不使用springboot时,需要将策略标识与对应实例直接在代码中写死,这种方式不利于拓展,每次增加策略后都要修改Map。所以强烈建议使用springboot,通过注解方式实现策略的自动注册。新增策略后springboot启动时会扫描策略并对其进行注册,不需要修改旧代码。
2.2代码实现
下面我们首先定义策略接口及策略实例,使用springboot框架时只需要在策略实例上增加Component注解,即可将实例注入到Map中。
1 2 3 4 5 6 7 8 9 10 11 12 13
|
public interface CSVParser { public static final String cvsSplitBy = "\\|";
void parseCsv(BufferedReader br, String fileType) throws IOException; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
|
@Component("City") public class CityParser implements CSVParser{ private Logger logger = LoggerFactory.getLogger(this.getClass()); @Override public ParseResult parseCsv(BufferedReader br, String fileType) throws IOException { logger.info("City"); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
|
@Component("Region") public class RegionParser implements CSVParser{ private Logger logger = LoggerFactory.getLogger(this.getClass());
@Override public void parseCsv(BufferedReader br, String fileType) throws IOException { logger.info("Region"); } }
|
其次,编写策略选择器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
@Component public class ParseStrategyContext { @Resource private final Map<String,CSVParser> selectParser=new ConcurrentHashMap();
public CSVParser select(String type){ return selectParser.get(type); } }
|
2.3拓展
当需求发生变化,需要增加新类型文件时,只需要新增一个策略实例即可,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
@Component("Room") public class RoomParser implements CSVParser{ private Logger logger = LoggerFactory.getLogger(this.getClass());
@Override public void parseCsv(BufferedReader br, String fileType) throws IOException { logger.info("Room"); } }
|
2.4调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| @SpringBootTest public class NewCsvParseTest {
String filePath = "d://temp";
@Autowired ParseStrategySelector strategySelector; @Test void parseCsv() { File file = new File(filePath); File[] childFiles = file.listFiles(); BufferedReader br; for (File childFile : childFiles) { List<String> fileNameList = Arrays.asList(childFile.getName().split("_")); String fileType=fileNameList.get(0); br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), "UTF-8")); CSVParser parser = strategySelector.select(fileType); ParseResult parseResult = parser.parseCsv(br, fileType); } } }
|
3.总结
通过使用策略模式模式,大大减少了代码中的 if-else 使用,代码更加优雅,便于扩展。其次,springboot框架能够更加高效的完成开发任务。