设计模式之策略模式应用

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中。

/**
 * 策略接口
 */
public interface CSVParser {
    public static final String cvsSplitBy = "\\|";
    /**
     * 
     * @param br
     * @param fileType
     */
    void parseCsv(BufferedReader br, String fileType) throws IOException;
}

/**
 * 策略实现 city_xxxxxx.csv文件
 */
@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");
        //这里实现csv格式解析以及后续处理,此处省略...
    }
}
/**
 * 策略实现 region_xxxxxx.csv文件
 */
@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");
        //这里实现csv格式解析以及后续处理,此处省略...
    }
}

其次,编写策略选择器

/**
 * 解析策略选择器
 */
@Component
public class ParseStrategyContext {
	//这里springboot会扫描已定义的策略,并注册到selectParser中
    @Resource
    private final Map<String,CSVParser> selectParser=new ConcurrentHashMap();

    /**
     * 根据资源类型选择对应的解析策略
     * @param type 资源类型
     * @return
     */
    public CSVParser select(String type){
        return selectParser.get(type);
    }
}

2.3拓展

当需求发生变化,需要增加新类型文件时,只需要新增一个策略实例即可,如下:

/**
 * 策略实现 room_xxxxxx.csv文件
 */
@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");
        //这里实现csv格式解析以及后续处理,此处省略...
    }
}

2.4调用


@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框架能够更加高效的完成开发任务。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值