You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java数字钱包Cash-In/Cash-Out重复代码重构最佳实践咨询

数字钱包Cash-In/Cash-Out重复代码重构方案

Controller层重构

原Controller中两个方法仅服务调用和异常声明有差异,可提取通用处理逻辑,减少重复代码:

@RestController
@RequestMapping("/wallet_transaction")
public class WalletTransactionController {

    private final WalletTransactionService walletTransactionService;
    private final WalletTransactionMapper walletTransactionMapper;

    // 构造注入(Spring推荐方式)
    public WalletTransactionController(WalletTransactionService walletTransactionService, WalletTransactionMapper walletTransactionMapper) {
        this.walletTransactionService = walletTransactionService;
        this.walletTransactionMapper = walletTransactionMapper;
    }

    @PutMapping("/cash-in/{walletId}")
    void cashIn(@PathVariable String walletId,
                @RequestBody @Valid WalletTransactionRequest request) throws WalletInactiveException {
        handleTransaction(walletId, request, TransactionType.CASH_IN);
    }

    @PutMapping("/cash-out/{walletId}")
    void cashOut(@PathVariable String walletId,
                 @RequestBody @Valid WalletTransactionRequest request) throws WalletInactiveException, InsufficientBalanceException {
        handleTransaction(walletId, request, TransactionType.CASH_OUT);
    }

    // 通用交易处理方法
    private void handleTransaction(String walletId, WalletTransactionRequest request, TransactionType type) throws WalletInactiveException, InsufficientBalanceException {
        WalletTransactionDto dto = walletTransactionMapper.walletTrRequestToWalletTrDto(request);
        walletTransactionService.processTransaction(walletId, dto, type);
    }
}

Service层重构

原Service中大量重复逻辑(钱包查询、激活验证、交易属性设置、保存交易、余额更新等),可通过提取通用方法+函数式接口封装差异化操作来重构:

1. 定义函数式接口封装差异化操作

@FunctionalInterface
interface TransactionOperation {
    void execute(WalletTransaction transaction, String iban);
}

2. 重构Service核心逻辑

@Service
public class WalletTransactionServiceImpl implements WalletTransactionService {

    private final WalletRepository walletRepository;
    private final WalletTransactionRepository walletTransactionRepository;
    private final DebitTransactionService debitTransactionService;
    private final WalletService walletService;
    private final WalletTransactionMapper walletTransactionMapper;

    // 构造注入依赖
    public WalletTransactionServiceImpl(WalletRepository walletRepository, WalletTransactionRepository walletTransactionRepository, DebitTransactionService debitTransactionService, WalletService walletService, WalletTransactionMapper walletTransactionMapper) {
        this.walletRepository = walletRepository;
        this.walletTransactionRepository = walletTransactionRepository;
        this.debitTransactionService = debitTransactionService;
        this.walletService = walletService;
        this.walletTransactionMapper = walletTransactionMapper;
    }

    @Transactional
    @Override
    public void processTransaction(String walletId, WalletTransactionDto dto, TransactionType type) throws WalletInactiveException, InsufficientBalanceException {
        WalletTransaction transaction = walletTransactionMapper.walletTransactionDtoToWalletTransaction(dto);
        Wallet wallet = walletRepository.findWalletByWalletId(walletId);
        
        // 通用验证:钱包是否激活
        validateWalletActive(wallet);
        // 差异化验证:仅Cash-Out需要检查余额
        if (TransactionType.CASH_OUT.equals(type)) {
            validateSufficientBalance(wallet, transaction.getTransactionAmount());
        }

        // 通用配置:设置交易基础属性
        configureTransaction(transaction, wallet, type);
        // 获取并执行差异化操作
        TransactionOperation operation = getTransactionOperation(type);
        operation.execute(transaction, wallet.getUser().getIban());

        // 通用操作:保存交易、更新余额
        walletTransactionRepository.save(transaction);
        walletService.updateBalance(walletId, (double) transaction.getTransactionAmount(), type);
    }

    // 提取钱包激活验证逻辑
    private void validateWalletActive(Wallet wallet) throws WalletInactiveException {
        if (!WalletStatus.ACTIVE.equals(wallet.getStatus())) {
            throw new WalletInactiveException(wallet.getName() + " 钱包已冻结,无法进行交易。请使用「启用钱包」API激活。");
        }
    }

    // 提取余额充足验证逻辑
    private void validateSufficientBalance(Wallet wallet, BigDecimal amount) throws InsufficientBalanceException {
        if (amount.compareTo(wallet.getBalance()) > 0) {
            throw new InsufficientBalanceException(wallet.getName() + " 钱包余额不足,可通过「现金存入」API充值。");
        }
    }

    // 提取交易属性配置逻辑
    private void configureTransaction(WalletTransaction transaction, Wallet wallet, TransactionType type) {
        transaction.setWallet(wallet);
        transaction.setWalletTransactionId(UUID.randomUUID().toString());
        transaction.setTransactionType(type);
    }

    // 根据交易类型返回对应操作
    private TransactionOperation getTransactionOperation(TransactionType type) {
        return switch (type) {
            case CASH_IN -> debitTransactionService::withdraw;
            case CASH_OUT -> debitTransactionService::deposit;
            default -> throw new IllegalArgumentException("不支持的交易类型: " + type);
        };
    }

    // 兼容原有方法(可选,无需保留可删除)
    @Override
    public void chashIn(String walletId, WalletTransactionDto dto) throws WalletInactiveException {
        processTransaction(walletId, dto, TransactionType.CASH_IN);
    }

    @Override
    public void cashOut(String walletId, WalletTransactionDto dto) throws WalletInactiveException, InsufficientBalanceException {
        processTransaction(walletId, dto, TransactionType.CASH_OUT);
    }
}

重构核心思路

  1. Controller层:将请求转换、服务调用等通用逻辑提取到私有方法,通过交易类型区分具体执行路径,消除重复代码。
  2. Service层:
    • 拆分通用逻辑与差异化逻辑,将验证、配置等重复代码独立为私有方法;
    • 用函数式接口封装withdraw/deposit这类差异化操作,避免冗余的条件分支;
    • 核心流程集中到单一方法,符合单一职责原则,后续新增交易类型只需扩展TransactionOperation和类型判断即可。

内容的提问来源于stack exchange,提问作者Mahzad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 10:13:21