SpringBoot使用设计模式一策略模式
一、前言
我现在需要实现一个关于交易的功能,这个功能大致用到的参数都一样,但是在交易类型上分为充值、转账、消费、退款和提现等。不同的交易申请流程都属于交易功能的一部分,但是结合业务后,逻辑算法都是基本独立的。
按照往常的写法,可能会出现如下的代码写法:
public String createOrder(OrderInfo orderInfo) {
if (orderInfo.getType().equals("deposit")) { // 充值
//...
} else if (orderInfo.getType().equals("withdraw")) { // 提现
//...
}
}
针对这种场景,我们可以使用策略模式可以。
二、策略模式
在策略模式(Strategy Pattern
)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。
在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的context
对象。策略对象改变context
对象的执行算法。
使用场景:
- 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
- 一个系统需要动态地在几种算法中选择一种。
- 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
注意事项:如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。
优点:
- 干掉繁琐的
if
、switch
判断逻辑; - 代码优雅、可复用、可读性好;
- 符合开闭原则,扩展性好、便于维护;
- 符合开闭原则;
缺点:
- 策略如果很多的话,会造成策略类膨胀;
- 使用者必须清楚所有的策略类及其用途;
三、案例
请求实体类,充值、体现的实体省略。
@ApiModel(value = "发起交易申请")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class TransactionApply implements Serializable {
@ApiModelProperty(value = "交易类型")
private Integer transactionMode;
@ApiModelProperty(value = "充值")
private DepositApply depositApply;
@ApiModelProperty(value = "提现")
private WithdrawApply withdrawApply;
}
交易的接口:
public interface TransactionService {
/**
* 交易类型
*
* @return
*/
TransactionModeEnum transactionMode();
/**
* 交易申请
*
* @param transactionApply
* @return
*/
R<?> transactionApply(TransactionApply transactionApply);
/**
* 确认支付(短信验证码确认)
*
* @param transactionVerify
* @return
*/
R<?> transactionVerify(TransactionVerify transactionVerify);
}
抽象类通用方法实现,充值、提现的公共方法,用于代码复用,比如获取交易订单支付验证码等。
public abstract class AbstractTransaction implements TransactionService {
/**
* 确认支付(短信验证码确认)
*
* @param transactionVerify
* @return
*/
@Override
public R<?> transactionVerify(TransactionVerify transactionVerify) {
//业务代码实现
}
}
充值service
具体实现类
@Service
@Slf4j
public class DepositApplyServiceImpl extends AbstractTransaction {
/**
* 交易类型
*
* @return
*/
@Override
public TransactionModeEnum transactionMode() {
return TransactionModeEnum.DEPOSIT;
}
/**
* 充值
*
* @param transactionApply
* @return
*/
@Override
public R<?> transactionApply(TransactionApply transactionApply) {
//业务代码实现
}
}
提现service
实现类
@Service
@Slf4j
public class WithdrawApplyServiceImpl extends AbstractTransaction {
/**
* 交易类型
*
* @return
*/
@Override
public TransactionModeEnum transactionMode() {
return TransactionModeEnum.WITHDRAW;
}
/**
* 提现
*
* @param transactionApply
* @return
*/
@Override
public R<?> transactionApply(TransactionApply transactionApply) {
//业务代码实现
}
}
枚举类
@Getter
@NoArgsConstructor
@AllArgsConstructor
public enum TransactionModeEnum {
DEPOSIT("1", "充值"),
WITHDRAW("2", "提现"),
;
private String code;
private String name;
}
Controller
调用
@RestController
@RequestMapping("/transaction")
public class TransactionController {
@Autowired
private List<TransactionService> transactionServiceList;
/**
* 交易申请
*/
@PostMapping("/transactionApply")
public R<?> transactionApply(@RequestBody TransactionApply transactionApply) {
Optional<TransactionService> transactionServiceOptional = transactionServiceList.stream()
.filter(t -> transactionApply.getTransactionMode()
.equals(t.transactionMode().getCode())).findAny();
if (transactionServiceOptional.isPresent()) {
return transactionServiceOptional.get().transactionApply(transactionApply);
}
return R.fail();
}
}
请求时需要传transactionMode
交易类型。
四、工厂模式
除上面的流实现外,还可以使用工厂类获取实现类。
比较关键的一点是AutoWired
一个Map<String, TransactionService>
这个会在初始化的时候将所有的TransactionService
自动加载到Map
中。
@Service
@Slf4j
public class TransactionFactory {
@Autowired //关键在这个,原理:当一个接口有多个实现类的时候,key为实现类名,value为实现类对象
private Map<String, TransactionService> transactionServiceMap = new ConcurrentHashMap<>(2);
public TransactionService getTransactionApply(String transactionMode) {
TransactionService transactionService = transactionServiceMap.get(transactionMode);
if(transactionService == null) {
throw new RuntimeException("no service defined");
}
return transactionService;
}
}
这里主要是获得相应的实现类,也可以通过其他方式获得,比如ApplicationContextUtil.getBean
。
控制层需要修改
@RestController
@RequestMapping("/transaction")
public class TransactionController {
@Autowired
private TransactionFactory transactionFactory;
/**
* 交易申请
*/
@PostMapping("/transactionApply")
public R<?> transactionApply(@RequestBody TransactionApply transactionApply) {
TransactionService transactionService = transactionFactory.get(
transactionApply.getTransactionMode());
return transactionService.transactionApply(transactionApply);
}
}
Service
实现类需要添加相应的value
值:
@Service("1")
@Slf4j
public class DepositApplyServiceImpl extends AbstractTransaction {
//...
}
@Service("2")
@Slf4j
public class WithdrawApplyServiceImpl extends AbstractTransaction {
//...
}
枚举类和transactionMode
方法就不需要了。