使用策略模式消除ifelse
有这样的场景,根据不同的套餐,有不同的计算方式,全部在一个函数里面,使用if+else不停的判断,导致一个方法堆了成百上千行,而且不同的service里面都有这个关于不同套餐的计算方式。为了解决这个问题,学习使用策略模式消除,使得代码遵 循开闭原则,新增新的套餐会变得容易
原则:修改关闭,扩展开放
策略模式
目前的代码:
现在有一个coding函数,我们想要根据传入的codeType来进行判断使用那个编辑器coding,如果这样ifelse写的话,每次新加一个编辑器,这边都要进行修改,不符合软件设计的开闭原则。
public void coding(String codeType) {
if (Objects.equals("IDEA", codeType)) {
System.out.println("使用IDEA编码");
} else if (Objects.equals("Eclipse", codeType)) {
System.out.println("使用Eclipse编码");
}
//...
}
修改
我们先定义一个编码接口
public interface Program {
void coding();
}
然后去实现不同种的编码方案:
public class Eclipse implements Program{
@Override
public void coding() {
System.out.println("使用Eclipse编码");
}
}
public class IDEA implements Program{
@Override
public void coding() {
System.out.println("使用IDEA编码");
}
}
使用
定义一个操作类,注入Program
private Program program;
public StrategyPattern(Program program) {
this.program = program;
}
public Program getProgram() {
return program;
}
public void setProgram(Program program) {
this.program = program;
}
public void startCoding(){
program.coding();
}
测试
public void coding(String codeType) {
switch (codeType) {
case "Eclipse":
new StrategyPattern(new Eclipse()).startCoding();
break;
case "IDEA":
new StrategyPattern(new IDEA()).startCoding();
break;
default:
System.out.println("使用其他IDE编码");
}
}
这样其实还是ifelse,但是代码会简洁很多更容易维护,下面进行消除
策略枚举
定义一个枚举类,表示有哪些分支:
public enum ProgramEnums {
ECLIPSE("Eclipse"),
IDEA("IDEA");
private String codeType;
ProgramEnums(String codeType) {
this.codeType = codeType;
}
public String getCodeType() {
return codeType;
}
}
定义一个工厂类,用来根据type获取对应的实现
public class ProgramFactory {
private static final Map<String, Program> PROGRAM_MAP = new HashMap<>();
static {
PROGRAM_MAP.put("Eclipse", new Eclipse());
PROGRAM_MAP.put("IDEA", new IDEA());
}
public static Map<String, Program> getProgramMap(String codeType) {
return PROGRAM_MAP;
}
}
使用:
public static void main(String[] args) {
String codeType = "IDEA";
Program programMap = ProgramFactory.getProgramMap(codeType);
programMap.coding();
}
策略模式+工厂模式+模版方法
上面的代码其实还是有点冗余问题,我们可以使用策略模式+工厂模式+模版方法接口,
定义接口
public interface Program {
void coding();
void testing();
ProgramEnums getProgramEnum();
}
定义模版方法
@Service
public abstract class AbstractProgram implements InitializingBean, Program {
@Override
public void coding() {
throw new UnsupportedOperationException("不支持的操作");
}
/**
* 禁止调用
*/
@Override
public void testing() {
throw new UnsupportedOperationException("不支持的操作");
}
// 子类必须提供枚举类型
@Override
public abstract ProgramEnums getProgramEnum();
@Override
public void afterPropertiesSet() throws Exception {
ProgramFactory.registerProgram(getProgramEnum().getCodeType(), this);
}
}
这里的好处是Service定义为Bean,然后通过afterPropertiesSet自动让子类把自己注册到Bean进行管理
定义工厂
@Component
public class ProgramFactory {
private static final Map<String, AbstractProgram> PROGRAM_MAP = new HashMap<>();
// 提供注册方法
public static void registerProgram(String codeType, AbstractProgram program) {
PROGRAM_MAP.put(codeType, program);
}
// 获取注册的Program
public static AbstractProgram getProgram(String codeType) {
AbstractProgram program = PROGRAM_MAP.get(codeType);
if (program == null) {
throw new IllegalArgumentException("Unsupported code type: " + codeType);
}
return program;
}
public static AbstractProgram getProgram(ProgramEnums programEnums) {
return getProgram(programEnums.getCodeType());
}
}
定义枚举
public enum ProgramEnums {
ECLIPSE("Eclipse"),
IDEA("IDEA");
private final String codeType;
ProgramEnums(String codeType) {
this.codeType = codeType;
}
public String getCodeType() {
return codeType;
}
}
实现策略IDEA
@Component
public class IDEAProgram extends AbstractProgram {
@Override
public void coding() {
System.out.println("IDEA编程");
}
@Override
public ProgramEnums getProgramEnum() {
return ProgramEnums.IDEA;
}
}
实现策略Eclipse
@Component
public class EclipseProgram extends AbstractProgram {
@Override
public void coding() {
System.out.println("Eclipse编程");
}
@Override
public ProgramEnums getProgramEnum() {
return ProgramEnums.ECLIPSE;
}
}
测试
@SpringBootTest
class MainTest {
@Test
void test() {
String codeType = "IDEA";
AbstractProgram program = ProgramFactory.getProgram(codeType);
program.coding();
}
}
结果: