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); } }
重构核心思路
- Controller层:将请求转换、服务调用等通用逻辑提取到私有方法,通过交易类型区分具体执行路径,消除重复代码。
- Service层:
- 拆分通用逻辑与差异化逻辑,将验证、配置等重复代码独立为私有方法;
- 用函数式接口封装
withdraw/deposit这类差异化操作,避免冗余的条件分支; - 核心流程集中到单一方法,符合单一职责原则,后续新增交易类型只需扩展
TransactionOperation和类型判断即可。
内容的提问来源于stack exchange,提问作者Mahzad
相关产品推荐
相关产品推荐

