下图为所有设计模式,带标记为重点掌握以及工作中常用到的:
策略模式是行为型设计模式之一,其作用是让一个类的行为或其算法可以在运行时更改,该模式也算是我比较熟悉的模式之一了,因为之前项目中有幸遇到大佬用过,然后学习了一下,后面会讲述策略模式我在项目中的实战使用场景。
模式名称 | 优点 | 缺点 | 应用场景 |
---|---|---|---|
策略模式 | 1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好 | 1、策略类会增多。 2、所有策略类都需要对外暴露。 | 1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。 2、一个系统需要动态地在几种算法中选择一种。 3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。 |
注意事项:如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题
策略模式Demo
1.创建一个策略接口
public interface Strategy {
public int doOperation(int num1, int num2);
}
2.创建多个接口的实现类
// 加法运算
public class OperationAdd implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
// 减法运算
public class OperationSubtract implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}
// 乘法运算
public class OperationMultiply implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 * num2;
}
}
3.创建 Context 类
public class Context {
private Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
public int executeStrategy(int num1, int num2){
return strategy.doOperation(num1, num2);
}
}
4.测试demo
public static void main(String[] args) {
Context context = new Context(new OperationAdd());
System.out.println("10 + 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationSubtract());
System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationMultiply());
System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
}
测试结果如下:
10 + 5 = 15
10 - 5 = 5
10 * 5 = 50
根据以上的demo案例我们可以看出来,策略模式的核心思想其实就是不同的行为会获取对应行为的类对象,从而获取该行为对应的结果。策略模式通常被用于进行解决在有多种算法相似的情况下,使用 if…else 所带来的复杂性和难以维护的问题。
策略模式实际案例一
1.使用背景
项目中开发工单模块时,遇到工单结单,此时结单的方式有多种,包括:现金支付、微信支付、支付宝支付、账户余额支付等等,并且各种结单方式也有不同的逻辑。此时我们应该如何书写结单接口呢,难道是根据结单类型去进行if else的判断书写吗?虽然这种方式最后也可以实现功能,但是代码维护起来就比较费劲了,而且也不便于以后的扩展,因此我们完全可以采用策略模式进行解决。以上代码为我们项目代码,不可以直接使用,大家可以参考。
2.示例代码
1.创建策略接口
public interface AppEndWorkOrderService {
/**
* APP-维修工单-结单
*
* @param id 工单ID
* @param order 订单信息
* @param callbackAddress 回调地址
* @return 成功/失败标志
* @date 2021/10/12 9:35
*/
R<Map<String, Object>> endWorkOrder(Long id, Order order, String callbackAddress);
}
2.创建接口的实现类(现金支付、支付宝支付)
/**
* 现金支付结单服务
*
* @author wyj
* @date 2021/10/12 9:38
*/
@Log4j2
@Service("appCashPayEndWorkOrderService")
public class AppCashPayEndWorkOrderServiceImpl implements AppEndWorkOrderService {
@Autowired private AppOrderRepairRecordService appOrderRepairRecordService;
@Autowired private ChargeCreateBizApi chargeCreateBizApi;
// 策略服务注册
static {
StrategyContext.registerProvider(
StrategyContext.PAY_TYPE + OrderPayTypeEnum.CASH_PAY.getValue(),
AppCashPayEndWorkOrderServiceImpl.class);
}
@Override
public R<Map<String, Object>> endWorkOrder(Long id, Order order , String callbackAddress) {
appOrderRepairRecordService.paySuccess(id, null, null);
// 生成缴费记录
ChargeCreateRequestDTO requestDTO = new ChargeCreateRequestDTO();
requestDTO.setBusinessNo(id);
requestDTO.setChargeChannel(ChargeChannelEnum.WX_MS);
requestDTO.setChargePayMethod(ChargePayMethodEnum.CASH);
chargeCreateBizApi.createByScene(requestDTO);
return R.success(null);
}
}
/**
* 支付宝结单服务
*
* @author wyj
* @date 2021/10/12 9:38
*/
@Log4j2
@Service("appAlipayPayEndWorkOrderServiceImpl")
public class AppAlipayPayEndWorkOrderServiceImpl implements AppEndWorkOrderService {
// 策略服务注册
static {
StrategyContext.registerProvider(
StrategyContext.PAY_TYPE + OrderPayTypeEnum.ALIPAY_PAY.getValue(),
AppAlipayPayEndWorkOrderServiceImpl.class);
}
@Override
public R<Map<String, Object>> endWorkOrder(Long id, Order order, String callbackAddress) {
// 支付宝支付后进行工单结单\订单结束等操作
return null;
}
}
3.创建工具类StrategyContext
@Component
public class StrategyContext {
// key
public static final String PAY_TYPE = "pay-type-";
// 策略映射map
private static final Map<String, Class<?>> providers = new HashMap<>();
// 提供给策略具体实现类的注册返回
public static void registerProvider(String subjectId, Class<?> provider) {
providers.put(subjectId, provider);
}
// 返回策略映射的具体服务
public static Object getService(String subjectId) {
Class<?> providerClazz = providers.get(subjectId);
return SpringContextHelper.getBean(providerClazz);
}
}
4.创建工具类
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class SpringContextHelper implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextHelper.applicationContext = applicationContext;
}
public static Object getBean(Class<?> clazz) throws BeansException {
return applicationContext.getBean(clazz);
}
public static Object getBean(String name) throws BeansException {
return applicationContext.getBean(name);
}
}
4.策略使用
策略模式实际案例二
1.使用背景
项目中进行指令数据打包时,根据不同的编号去选择不同的实现类去完成数据打包,此处也选择使用策略模式完成,但是实现方式和第一个稍微有些区别。大家可以参考一下;
2.示例代码
1.创建一个待实现的接口
public interface DataPack {
String packClickCmd(String cmdCode);
}
2.分别创建2个不同的实现类DataPackHandler和NewFlowMeterDataPackHandler
import org.springframework.stereotype.Service;
@Service(DataPackHandlerContext.POLICY_PREFIX + 100)
public class DataPackHandler implements DataPack {
public String packClickCmd(String cmdCode) {
cmdCode = "DataPackHandler:" + cmdCode;
System.out.println(cmdCode);
return cmdCode;
}
}
import org.springframework.stereotype.Service;
@Service(DataPackHandlerContext.POLICY_PREFIX + 101)
public class NewFlowMeterDataPackHandler implements DataPack {
public String packClickCmd(String cmdCode) {
cmdCode = "NewFlowMeterDataPackHandler:" + cmdCode;
System.out.println(cmdCode);
return cmdCode;
}
}
3.创建一个策略模式的工具类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 指令打包策略工具类
*
* @date 2022/7/22 10:37
*/
@Component
public class DataPackHandlerContext {
@Autowired
private Map<String, DataPack> dataPackMap = new ConcurrentHashMap<>();
public static final String POLICY_PREFIX = "pack";
/**
* 根据协议数据解析对应实例
*
* @param protocolVersion
* @return
*/
public DataPack getDataPack(String protocolVersion) {
return dataPackMap.get(POLICY_PREFIX + protocolVersion);
}
}
4.使用策略模式
import com.weiyiji.exception.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@Autowired
private DataPackHandlerContext dataPackHandlerContext;
@GetMapping("/getName")
public R<String> getName(String version) {
DataPack dataPack = dataPackHandlerContext.getDataPack(version);
String test = dataPack.packClickCmd("test");
return R.success(test);
}
}
5.结果展示
小结
本实例中就是在同一个接口中根据不同的支付方式获取对应支付方式对应的实体类对象,然后进行其后续操作。