优化过长的“分支代码”
基于多态
假设有一段“分支代码”(片段 1):
// 可能的 Case
CaseEnum caseEnum = getRandomCase();
if (CaseEnum.AA.equals(caseEnum)) {
// ...
} else if (CaseEnum.BB.equals(caseEnum)) {
// ...
} else if (CaseEnum.CC.equals(caseEnum)) {
// ...
}
其等效代码类似于(片段 2):
// 可能的 Case
CaseEnum caseEnum = getRandomCase();
for (CaseHandler handler : caseHandlerFactory.getHandlers()) {
if (handler.match(caseEnum)) {
handler.handle();
break;
}
}
当增加分支的时候,片段 1 需要在尾部追加代码,而片段 2 无需变更,前提是片段 2 依赖更多的类。
注意:片段 2 在最坏情况下的运行时间的增长数量级是 N。
如何实现?
(一)CaseHandler。
public interface CaseHandler {
/**
* 匹配 Case。
*
* @param caseEnum Case 枚举
* @return 是否
*/
boolean match(CaseEnum caseEnum);
/**
* 业务处理。
*/
void handle();
}
(二)CaseHandler 实现之一。
public class AaHandler implements CaseHandler {
@Override
public boolean match(CaseEnum caseEnum) {
return CaseEnum.AA.equals(caseEnum);
}
@Override
public void handle() {
// ...
}
}
(三)CaseHandler 工厂。
public class CaseHandlerFactory {
/**
* handler name to handler
*/
private final Map<String, CaseHandler> name2Handler;
public CaseHandlerFactory() {
this.name2Handler = new LinkedHashMap<>();
}
public CaseHandlerFactory addHandler(CaseHandler handler) {
if (Objects.isNull(handler)) {
return this;
}
name2Handler.put(handler.getClass().getSimpleName(), handler);
return this;
}
public Collection<CaseHandler> getHandlers() {
return name2Handler.values();
}
}
(四)初始化 CaseHandler 工厂。
final CaseHandlerFactory caseHandlerFactory = new CaseHandlerFactory()
.addHandler(new AaHandler())
.addHandler(new BbHandler())
.addHandler(new CcHandler())
;
依赖注入
基于 Spring IoC,自动实例化 CaseHandler 工厂。
(一)将 CaseHandler 的所有实现声明为 Spring Bean。
@Component
public class AaHandler implements CaseHandler {
@Override
public boolean match(CaseEnum caseEnum) {
return CaseEnum.AA.equals(caseEnum);
}
@Override
public void handle() {
// ...
}
}
(二)CaseHandlerFactory 构造器的依赖注入。
@Component
public class CaseHandlerFactory {
/**
* handler name to handler
*/
private final Map<String, CaseHandler> name2Handler;
@Autowired
public CaseHandlerFactory(Collection<CaseHandler> handlers) {
Assert.notNull(handlers, "handlers must not be null");
this.name2Handler = new LinkedHashMap<>(handlers.size());
handlers.forEach(this::addHandler);
}
public void addHandler(CaseHandler handler) {
if (Objects.isNull(handler)) {
return;
}
name2Handler.put(handler.getClass().getSimpleName(), handler);
}
public Collection<CaseHandler> getHandlers() {
return name2Handler.values();
}
}
(三)引用 CaseHandlerFactory。
@Resource
private CaseHandlerFactory caseHandlerFactory;
策略模式
基于 Spring Boot 开发 Web 程序时,有时会遇到需要根据不同的类型或策略(strategy)做不同的事情,例如:
@RestController
@RequestMapping("/some")
public class SomeController {
@Resource
private SomeService someService;
@PostMapping("/doSomething")
public ResponseEntity<?> doSomething(@RequestBody Some some) {
someService.doSomething(some);
return ResponseEntity.ok().build();
}
}
@Service
public class SomeService {
public void doSomething(Some some) {
StrategyEnum strategyEnum = some.getStrategyEnum();
Assert.notNull(strategyEnum, "strategyEnum must not be null");
switch (strategyEnum) {
case Strategy1:
// ...
break;
case Strategy2:
// ...
break;
case Strategy3:
// ...
break;
default:
// ...
}
}
}
使用策略模式可以优化过长的“分支代码”。
Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
大同小异,编写策略类和策略工厂类。
(一)所有可能的 Strategy。
public enum StrategyEnum {
Strategy1,
Strategy2,
Strategy3
// ...
}
(二)Strategy 接口。
public interface Strategy {
/**
* 获取 Strategy 枚举
*
* @return Strategy 枚举
*/
StrategyEnum getStrategyEnum();
/**
* 业务处理
*/
void doSomething();
}
(三)Strategy 的其中一个实现。
@Component
public class Strategy1 implements Strategy {
@Override
public StrategyEnum getStrategyEnum() {
return StrategyEnum.Strategy1;
}
@Override
public void doSomething() {
// ...
}
}
(四)Strategy 工厂。
@Component
public class StrategyFactory {
private final Map<StrategyEnum, Strategy> strategyMap;
@Autowired
public StrategyFactory(Collection<Strategy> strategies) {
Assert.notNull(strategies, "strategies must not be null");
this.strategyMap = new LinkedHashMap<>(strategies.size());
strategies.forEach((strategy) -> strategyMap.put(strategy.getStrategyEnum(), strategy));
}
public Strategy getStrategy(StrategyEnum strategyEnum) {
return strategyMap.get(strategyEnum);
}
}
(五)重写 SomeService。
@Service
public class SomeService {
@Resource
private StrategyFactory strategyFactory;
public void doSomething(Some some) {
Strategy strategy = strategyFactory.getStrategy(some.getStrategyEnum());
if (Objects.nonNull(strategy)) {
strategy.doSomething();
}
}
}
注意:获取策略的方法(getStrategy)在最坏情况下的运行时间的增长数量级是 1。
本文首发于 https://h2cone.github.io/