策略模式(Strategy Pattern)
定义:
定义了一组算法,将每个算法都封装起来,并且使它们之间可以互换。
本质:
分离算法,选择实现
应用场景
何时使用
一个系统有许多类,而区分他们的只是他们直接的行为时
优点
开闭原则
避免使用多重条件判断
扩展性良好,增加一个策略只需要实现接口即可
缺点
策略类数量会增多,复用可能性很小
所有策略类都需要对外暴露
场景
多个类,只有算法或行为上稍有不同的场景
算法需要自由切换的场景
需要屏蔽算法规则
实例举例
导入导出
出行方式:自行车、汽车等,每一种出行方式都是一个策略
商场促销方式,打折、满减等
Java LayoutManager 布局管理器
…
策略模式实现导入/导出
背景:最近在做excle的导入导出,大概10个导出,3个导入。共用的同一个记录表。思来想去用策略+简单工厂模式去除if else if …,以便更好的拓展和维护。
1.定义一个导入接口:
**
2.创建一个策略工厂:
@Resourceprivate Map<String, TaskExportHandleService> taskHandleServiceMap;
3.策略枚举:
@Getter
public enum TaskTypeEnum {/*** 任务类型枚举*/DAILY(1, "日常检查"),SPECIAL(2, "专项检查"),ENTERPRISE(3, "企业自查"),;private final Integer code;private final String desc;TaskTypeEnum(int code, String desc) {this.code = code;this.desc = desc;}public static TaskTypeEnum toEnum(int id) {return Arrays.stream(values()).filter(area -> area.getCode().equals(id)).findFirst().orElse(null);}
}
4.实现接口:
@Service("ENTERPRISE")
@Slf4j
public class EnterpriseTaskExportHandleServiceImpl implements TaskExportHandleService {@Overridepublic Long saveRecord(Map<String, Object> paramMap, String operator) {log.info("------------------------");log.info("执行任务:{}", TaskTypeEnum.ENTERPRISE.getDesc());log.info("保存记录文件,状态置为处理中");return 0L;}@Async("TaskExport")@Overridepublic void exportFile(Map<String, Object> paramMap, Long recordId, EpUser currentUser) {log.info("异步处理导出文件ing");log.info("更新到文件记录ing");log.info("------------------------");}
}@Service("DAILY")
@Slf4j
public class DailyTaskExportHandleServiceImpl implements TaskExportHandleService {@Overridepublic Long saveRecord(Map<String, Object> paramMap, String operator) {log.info("------------------------");log.info("执行任务:{}", TaskTypeEnum.DAILY.getDesc());log.info("保存记录文件,状态置为处理中");return 0L;}@Async("TaskExport")@Overridepublic void exportFile(Map<String, Object> paramMap, Long recordId, EpUser currentUser) {log.info("异步处理导出文件ing");log.info("更新到文件记录ing");log.info("------------------------");}
}@Service("SPECIAL")
@Slf4j
public class SpecialTaskExportHandleServiceImpl implements TaskExportHandleService {@Overridepublic Long saveRecord(Map<String, Object> paramMap, String operator) {log.info("------------------------");log.info("执行任务:{}", TaskTypeEnum.SPECIAL.getDesc());log.info("保存记录文件,状态置为处理中");return 0L;}@Async("TaskExport")@Overridepublic void exportFile(Map<String, Object> paramMap, Long recordId, EpUser currentUser) {log.info("异步处理导出文件ing");log.info("更新到文件记录ing");log.info("------------------------");}
}
5.1controller 实现:
@RestController
@RequestMapping("/demo")
//@RequiredArgsConstructor 需要final
@AllArgsConstructor
@Anonymous
@Slf4j
public class TaskController {private final List<TaskExportHandler> exportHandlers;private final DefaultExportHandler defaultExportHandler;@PostMapping("/export")public Result<String> list(@RequestBody TaskExportReq req) {exportHandlers.stream().filter(fileHandler ->fileHandler.support(req.getBusinessType())).findFirst().orElse(defaultExportHandler).exportFile(req.getBusinessType(),new EpUser(), req.getParamMap());return Result.success(null);}
}
5.2导出文件req
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ApiModel("导出文件req")
public class TaskExportReq {@ApiModelProperty(value = "操作类型枚举 TaskTypeEnum")private Integer businessType;@ApiModelProperty(value = "查询参数")private Map<String, Object> paramMap;}
6.1方便维护,编写任务导出Handler
@Component
public abstract class TaskExportHandler {@Resourceprivate Map<String, TaskExportHandleService> taskHandleServiceMap;public void exportFile(Integer businessType, EpUser currentUser, Map<String, Object> paramMap) {// 匹配处理器TaskExportHandleService taskExportHandleService = matchExportService(businessType);// 保存记录-调用保存文件Long recordId = taskExportHandleService.saveRecord(paramMap, currentUser.getName());// 异步执行导出taskExportHandleService.exportFile(paramMap, recordId, currentUser);}/*** 匹配业务类型对应的导出处理器*/private TaskExportHandleService matchExportService(Integer businessType) {TaskTypeEnum businessTypeEnum = TaskTypeEnum.toEnum(businessType);if (Objects.isNull(businessTypeEnum) || Objects.isNull(taskHandleServiceMap.get(businessTypeEnum.name()))) {throw new ServiceException("不支持的文件操作类型");}return taskHandleServiceMap.get(businessTypeEnum.name());}public Boolean support(Integer businessType) {return Boolean.FALSE;}
}
6.2默认任务Handler
@Component
public class DefaultExportHandler extends TaskExportHandler {}
7运行效果: