SpringBoot使用设计模式一策略模式

一、前言

我现在需要实现一个关于交易的功能,这个功能大致用到的参数都一样,但是在交易类型上分为充值、转账、消费、退款和提现等。不同的交易申请流程都属于交易功能的一部分,但是结合业务后,逻辑算法都是基本独立的。

按照往常的写法,可能会出现如下的代码写法:

public String createOrder(OrderInfo orderInfo) {
    
    if (orderInfo.getType().equals("deposit")) {            // 充值
        //...
    } else if (orderInfo.getType().equals("withdraw")) {    // 提现
        //...
    }
}

针对这种场景,我们可以使用策略模式可以。

二、策略模式

在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。

在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的context对象。策略对象改变context对象的执行算法。

使用场景:

  1. 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
  2. 一个系统需要动态地在几种算法中选择一种。
  3. 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。

注意事项:如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。

优点:

  1. 干掉繁琐的ifswitch判断逻辑;
  2. 代码优雅、可复用、可读性好;
  3. 符合开闭原则,扩展性好、便于维护;
  4. 符合开闭原则;

缺点:

  1. 策略如果很多的话,会造成策略类膨胀;
  2. 使用者必须清楚所有的策略类及其用途;

三、案例

请求实体类,充值、体现的实体省略。

@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方法就不需要了。

posted @ 2022-04-25 16:47  夏尔_717  阅读(1413)  评论(0编辑  收藏  举报