策略模式的优点有:策略模式提供了管理相关的算法族的办法、策略模式提供了可以替换继承关系的办法、使用策略模式可以避免使用多重条件转移语句。
策略模式有三个部分组成:
—抽象策略角色: 策略类,通常由一个接口或者抽象类实现。
—具体策略角色:包装了相关的算法和行为。—环境角色:持有一个策略类的引用,最终给客户端调用
下面举个策略模式在项目中实际应用的例子。在Java后台项目中,一般都有将Excel表格导入的需求,这里必须想到在不同的模块中需要导入的数据也是不同的,但是导入需要的方法却是通用的,比如都需要先导出一个Excel表格作为数据写入的模版,比如都需要导出Excel表格中填写不正确的数据等等。。。
1. 首先定义一个策略类,也就是下面的ExcelOperation 接口
public interface ExcelOperation { /** * 得到导入数据的模板 */ void getExcelTemplate(String moduleName); /** * 预览excel表格数据 * @param excel * @return */ Object previewExcelData(MultipartFile excel,String moduleName); /** * 导出excel表格中格式错误数据 */ void exportExcelErrorData(String moduleName); /** * 导入excel表格正确数据进入数据库 */ Object importExcelCorrectData(String moduleName); } |
这里每个函数都有一个参数为moduleName,这就是为了自动的根据你传入的moduleName去调用相应模块的方法
2.具体的策略角色 也就是实现上述接口的类
@Service("lineExcel") public class LineExcelImpl extends BaseExcel implements ExcelOperation{ @Override public void getExcelTemplate(String moduleName) { String colName[] = { "线路名称", "系统", "规则模式","系统版本", "备注","描述" }; try { generateImportExcel("lineExcelTemple",colName,true); } catch (IOException e) { logger.error("LineExcelImpl'getExcelTemplate has error",e); } } @Override public Object previewExcelData(MultipartFile excel, String moduleName) { ........ } @Override public void exportExcelErrorData(String moduleName) { ........ } @Override public Object importExcelCorrectData(String moduleName) { ....... } } |
上述的策略实现类继承了一个BaseExcel类 ,这只是一个封装了一些导入excel表格时需要用到的方法的工具类。这里还用注解的方式将这个实现类放入了容器中。
3.环境角色,持有一个策略类的引用,最终给客户端调用
@Component public class ExcelOperationAdapter implements ExcelOperation,ApplicationContextAware { private ApplicationContext appContext; private ExcelOperationAdapter(){} private ExcelOperation getExcelOperationImpl(String moduleName){ return (ExcelOperation)appContext.getBean(moduleName); } @Override public void getExcelTemplate(String moduleName) { getExcelOperationImpl(moduleName).getExcelTemplate(moduleName); } @Override public Object previewExcelData(MultipartFile excel,String moduleName) { return getExcelOperationImpl(moduleName).previewExcelData(excel,moduleName); } @Override public void exportExcelErrorData(String moduleName) { getExcelOperationImpl(moduleName).exportExcelErrorData(moduleName); } @Override public Object importExcelCorrectData(String moduleName) { return getExcelOperationImpl(moduleName).importExcelCorrectData(moduleName); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.appContext=applicationContext; } } |
在这里,我们的环境角色类除了实现了策略接口外,还实现了ApplicationContextAware 接口,实现这个接口的意义所在就是Spring容器会在创建该Bean之后,自动调用该Bean的setApplicationContextAware()方法,调用该方法时,会将容器本身作为参数传给该方法——该方法中的实现部分将Spring传入的参数(容器本身)赋给该类对象的appContext实例变量,因此接下来可以通过该appContext实例变量来访问容器本身.
这样的话,我们每实现一个策略实现类的时候,用声明式注解将这个实现类注入到容器中,注意到我们的策略中每个方法都有一个moduleName参数,这个参数就是声明式注解的名字。
4.在controler层调用实现类方法。
@Autowired private ExcelOperationAdapter excelOperationAdapter; private static final String LINE_EXCEL_IMPL="lineExcel"; excelOperationAdapter.getExcelTemplate(LINE_EXCEL_IMPL); |