在代码逻辑中,如果需要根据不同的条件执行不同的代码逻辑,我们最容易想到的就是使用if-else结构去进行判断,代码结构如下图所示:
if (condition1) {
// todo
} else if (condition2) {
// todo
} else if (condition3) {
// todo
} else if (condition4) {
// todo
}
在后续业务迭代的过程当中,如果需要增加新的逻辑判断和处理,我们就需要在原代码的基础上再增加新的分支,这样违背了面向对象设计中的开闭原则(Open-Close Principle),即对扩展开放,对修改关闭。面对这种分支判断较多的场景,在系统设计时我们可以引入设计模式中的策略模式,其类图关系如下所示:
策略模式的设计中包含三个角色:
- 抽象策略角色:一般定义成一个接口或者抽象类;
- 具体策略角色:封装具体的算法逻辑,即具体分支逻辑的代码实现;
- 环境角色:有时也称上下文角色,是具体策略的持有者;
下面以SpringBoot项目为例来说明策略模式的编写:
抽象策略类:
public interface ModuleAssembleStrategy {
/**
* Description: 填充模板信息
*/
List<Map<String, Object>> fillModuleInfo(String moduleTemplateValue);
}
具体的策略实现类:
@Service(value = "todayModuleStrategy")
public class TodayModuleStrategy implements ModuleAssembleStrategy {
@Autowired
private RemoteCallService remoteCallService;
@Override
public List<Map<String, Object>> fillModuleInfo(String moduleTemplateValue) {
// todo
}
}
@Service(value = "hotModuleStrategy")
public class HotModuleStrategy implements ModuleAssembleStrategy {
@Autowired
private RemoteCallService remoteCallService;
@Override
public List<Map<String, Object>> fillModuleInfo(String moduleTemplateValue) {
// todo
}
}
@Service(value = "masterModuleStrategy")
public class MasterModuleStrategy implements ModuleAssembleStrategy {
@Autowired
private RemoteCallService remoteCallService;
@Override
public List<Map<String, Object>> fillModuleInfo(String moduleTemplateValue) {
// todo
}
}
上下文环境角色:
public class ModuleAssembleContext {
private ModuleAssembleStrategy moduleAssembleStrategy;
public ModuleAssembleContext(ModuleAssembleStrategy moduleAssembleStrategy) {
this.moduleAssembleStrategy = moduleAssembleStrategy;
}
public List<Map<String, Object>> executeStrategy(String moduleTemplateValue) {
return moduleAssembleStrategy.fillModuleInfo(moduleTemplateValue);
}
}
在service层的具体使用:
@Service
public class ModuleAssembleServiceImpl implements ModuleAssembleService {
@Autowired
private ApplicationContext applicationContext;
@Autowired
private ModuleConfigProps moduleConfigProps;
@Override
public List<Map<String, Object>> fillModuleIfno(Integer moduleId, String moduleTemplateValue) {
// 通过反射获取具体策略类的实例bean
String fieldName = "module" + moduleId;
String firstLetter = fieldName.substring(0, 1).toUpperCase();
String getter = "get" + firstLetter + fieldName.substring(1);
Method method = moduleConfigProps.getClass().getMethod(getter, new Class[] {});
String beanName = (String) method.invoke(moduleConfigProps, new Object[] {});
ModuleAssembleStrategy moduleAssembleStrategy = applicationContext.getBean(beanName);
ModuleAssembleContext moduleAssembleContext = new ModuleAssembleContext(moduleAssembleStrategy);
return moduleAssembleContext.executeStrategy(moduleTemplateValue);
}
}
具体的配置类如下:
@Data
@Component
@ConfigurationProperties(prefix = "custom.module")
public class ModuleConfigProps {
private String module1;
private String module2;
private String module3;
}
配置文件application.yml如下:
custom:
module:
module1: todayModuleStrategy
module2: hotModuleStrategy
module3: masterModuleStrategy