在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。
在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。
优点: 1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。
缺点: 1、策略类会增多。 2、所有策略类都需要对外暴露。
使用场景: 1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。 2、一个系统需要动态地在几种算法中选择一种。
if else模式
if ("BATCH_CHANGE_WAREHOUSE".equals(taskType)) {
//批量转仓逻辑
} else if ("BATCH_CHANGE_SHIPPING".equals(taskType)) {
//批量转快递逻辑
} else if ("BATCH_REPLACE_ORDER_GOODS".equals(taskType)) {
//批量替换订单商品逻辑
} else if ("BATCH_DELETE_ORDER_GOODS".equals(taskType)) {
//批量删除订单商品逻辑
} else if ("BATCH_ADD_MEMO".equals(taskType)) {
//批量添加备注逻辑
} else {
//任务类型未知
System.out.println("任务类型无法处理");
}
看起来,思路清晰,if,else分支也很清楚,但不觉得代码很臃肿,维护起来麻烦吗,尤其是其他人来接锅的时候,连看下去的欲望都没有了。这时候你需要用策略模式消除其中的if else,进行一下简单的重构!
策略模式
1、首先抽象业务处理器
public abstract class InspectionSolver {
public abstract void solve(Long orderId, Long userId);
public abstract String[] supports();
}
2、将业务处理器和其支持处理的类型放到一个容器中,java里Map就是最常用的容器之一
@Component
public class InspectionSolverChooser implements ApplicationContextAware{
private Map<String, InspectionSolver> chooseMap = new HashMap<>();
public InspectionSolver choose(String type) {
return chooseMap.get(type);
}
@PostConstruct
public void register() {
Map<String, InspectionSolver> solverMap = context.getBeansOfType(InspectionSolver.class);
for (InspectionSolver solver : solverMap.values()) {
for (String support : solver.supports()) {
chooseMap.put(support,solver);
}
}
}
private ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context=applicationContext;
}
}
这里是在应用启动的时候,加载spring容器中所有InspectionSolver类型的处理器,放到InspectionSolverChooser的map容器中。注意是InspectionSolver类型,所以定义的处理器都得继承InspectionSolver,其次是spring容器中的才能加载,所以定义的处理器都得放到spring容器中(@Component注解不能少)
3、定义不同的处理器
@Component
public class ChangeWarehouseSolver extends InspectionSolver {
@Override
public void solve(Long orderId, Long userId) {
System.out.println("订单"+orderId+"开始进行批量转仓了。。");
}
@Override
public String[] supports() {
return new String[] {InspectionConstant.INSPECTION_TASK_TYPE_BATCH_CHANGE_WAREHOUSE};
}
}
@Component
public class ChangeShippingSolver extends InspectionSolver{
@Override
public void solve(Long orderId, Long userId) {
System.out.println("订单"+orderId+"开始进行转快递了。。");
}
@Override
public String[] supports() {
return new String[] {InspectionConstant.INSPECTION_TASK_TYPE_BATCH_CHANGE_SHIPPING};
}
}
@Component
public class ReplaceOrderGoodsSolver extends InspectionSolver{
@Override
public void solve(Long orderId, Long userId) {
System.out.println("订单"+orderId+"开始进行替换商品了");
}
@Override
public String[] supports() {
return new String[]{InspectionConstant.INSPECTION_TASK_TYPE_BATCH_REPLACE_ORDER_GOODS};
}
}
4、测试类
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes=Application.class)// 指定spring-boot的启动类
public class InspectionTest {
@Autowired
private InspectionSolverChooser chooser;
@Test
public void test() throws Exception{
//准备数据
String taskType = InspectionConstant.INSPECTION_TASK_TYPE_BATCH_CHANGE_WAREHOUSE;
Long orderId = 12345L;
Long userId = 123L;
//获取任务类型对应的solver
InspectionSolver solver = chooser.choose(taskType);
if (solver == null) {
throw new RuntimeException("任务类型暂时无法处理!");
}
//调用不同solver的方法进行处理
solver.solve(orderId,userId);
}
}
在测试类中我消除了可能一长段的if else,从选择器InspectionSolverChooser中根据type的不同取出不同的任务处理器InspectionSolver,然后调用其solve()方法进行任务处理,不同处理器调用的当然就是不同的solve()方法了,目的达到。