我们在做项目时,很多情况会根据不同的条件处理不同的逻辑,难免会出现大量的 if-else逻辑判断,条件多的时候,判断分支庞大,就会显得臃肿丑陋。使用设计模式之策略模式,就可以帮我们美化代码。
策略模式作为一种软件设计模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。比如每个人都要交个人所得税,但是在美国交个人所得税和在中国交个人所得税就有不同的算税方法。
在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。
策略模式由以下3种角色组成:
策略模式一般都是使用在不同策略(不同 if-else 方法体内容)比较复杂或者要执行不同操作等,分别需要大段代码的情况。
案例:服务端接收浏览器传来的字符串 a、b、operator,operator 值有 add、subtract、multiply 和 divide。服务端根据不同的 operator 值对 a 和 b 做拼接处理并返回。具体实现过程如下所示。
github 源码地址:https://github.com/piaoranyuji/strategy
git 仓库地址:[email protected]:piaoranyuji/strategy.git
package com.test.strategy.service;
/**
* @description 定义策略接口,后面所有策略要实现它
* @date 2019/12/19 16:00
*/
public interface Strategy {
String operateStr(String a, String b);
}
package com.test.strategy.service;
/**
* @description 编写具体策略类,具体策略中实现接口的方法,返回 add 操作结果
* @date 2019/12/19 16:05
*/
public class AddStrategy implements Strategy {
@Override
public String operateStr(String a, String b) {
return a + "+" + b;
}
}
package com.test.strategy.service;
/**
* @description 编写具体策略类,具体策略中实现接口的方法,返回 subtract 操作结果
* @date 2019/12/19 16:05
*/
public class SubtractStrategy implements Strategy {
@Override
public String operateStr(String a, String b) {
return a + "-" + b;
}
}
package com.test.strategy.service;
/**
* @description 编写具体策略类,具体策略中实现接口的方法,返回 multiply 操作结果
* @date 2019/12/19 16:05
*/
public class MultiplyStrategy implements Strategy {
@Override
public String operateStr(String a, String b) {
return a + "*" + b;
}
}
package com.test.strategy.service;
/**
* @description 编写具体策略类,具体策略中实现接口的方法,返回 divide 操作结果
* @date 2019/12/19 16:05
*/
public class DivideStrategy implements Strategy {
@Override
public String operateStr(String a, String b) {
return a + "/" + b;
}
}
package com.test.strategy.bean;
/**
* @description 定义枚举类,枚举不同的操作规则
* @date 2019/12/19 19:37
*/
public enum OperatorEnum {
ADD("com.test.strategy.service.AddStrategy"),
SUBTRACT("com.test.strategy.service.AddStrategy"),
MULTIPLY("com.test.strategy.service.AddStrategy"),
DIVIDE("com.test.strategy.service.DivideStrategy");
String value;
OperatorEnum(String value) {
this.value = value;
}
public String getvalue() {
return this.value;
}
}
package com.test.strategy.service;
import com.test.strategy.bean.OperatorEnum;
import lombok.extern.slf4j.Slf4j;
/**
* @description 创建工厂方法,创建具体策略类
* @date 2019/12/19 20:14
*/
@Slf4j
public class StrategyFacade {
/**
* 根据 operator 生成实际的操作策略,执行对应的方法
*
* @param a 字符串a
* @param b 字符串b
* @param operator 操作规则
* @return 处理后的字符串
*/
public static String doOperate(String a, String b, String operator) {
Strategy strategy;
try {
strategy = (Strategy) Class.forName(getStrategyType(operator).getvalue()).newInstance();
return strategy.operateStr(a, b);
} catch (Exception e) {
log.error("生成操作策略出现异常", e);
return "不合法的操作符";
}
}
/**
* 根据不同 operator 值生成不同的策略(策略场景变化时需要修改)
*
* @param operator 操作规则
* @return OperatorEnum 枚举对象
*/
private static OperatorEnum getStrategyType(String operator) {
if ("add".equals(operator)) {
return OperatorEnum.ADD;
} else if ("subtract".equals(operator)) {
return OperatorEnum.SUBTRACT;
} else if ("multiply".equals(operator)) {
return OperatorEnum.MULTIPLY;
} else if ("divide".equals(operator)) {
return OperatorEnum.DIVIDE;
} else {
return null;
}
}
}
3种不同的方法分别对业务需求做处理:
package com.test.strategy.controller;
import com.test.strategy.service.StrategyFacade;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* @description 策略模式测试类
* @date 2019/12/19 14:41
*/
@RestController
@Slf4j
public class TestController {
/**
* if-else 方式实现的两个字符串的不同拼接方法
*
* @param a 字符串a
* @param b 字符串b
* @param operator 操作规则
* @return 处理后的字符串
*/
@RequestMapping(value = "/test1", method = RequestMethod.GET)
public String test1(String a, String b, String operator) {
log.info("test1接收参数:a={};b={};operator={}", a, b, operator);
String result;
if ("add".equals(operator)) {
result = a + "+" + b;
} else if ("subtract".equals(operator)) {
result = a + "-" + b;
} else if ("multiply".equals(operator)) {
result = a + "*" + b;
} else if ("divide".equals(operator)) {
result = a + "/" + b;
} else {
result = "不合法的操作符";
}
return result;
}
/**
* switch 语句实现的两个字符串的不同拼接方法
*
* @param a 字符串a
* @param b 字符串b
* @param operator 操作规则
* @return 处理后的字符串
*/
@RequestMapping(value = "/test2", method = RequestMethod.GET)
public String test2(String a, String b, String operator) {
log.info("test2接收参数:a={};b={};operator={}", a, b, operator);
String result;
switch (operator) {
case "add":
result = a + "+" + b;
break;
case "subtract":
result = a + "-" + b;
break;
case "multiply":
result = a + "*" + b;
break;
case "divide":
result = a + "/" + b;
break;
default:
result = "不合法的操作符";
break;
}
return result;
}
/**
* 策略模式+工厂模式 实现的两个字符串的不同拼接方法
*
* @param a 字符串a
* @param b 字符串b
* @param operator 操作规则
* @return 处理后的字符串
*/
@RequestMapping(value = "/test3", method = RequestMethod.GET)
public String test3(String a, String b, String operator) {
log.info("test3接收参数:a={};b={};operator={}", a, b, operator);
return StrategyFacade.doOperate(a, b, operator);
}
}
// 测试结果:浏览器输入http://localhost:9999/test3?a=str1&&b=str2&&operator=divide,后端打印结果如下:
// test3接收参数:a=str1;b=str2;operator=divide
// 浏览器获取应答数据:str1/str2