当前位置: 首页 > news >正文

【设计模式】策略模式+门面模式设计对接银行接口的API

文章目录

    • 背景
    • 一、定义银行操作的统一接口(策略接口)
    • 二、各银行实现类
      • 工商银行
      • 农业银行
      • 建设银行
    • 三、银行类型枚举
    • 四、统一的请求和响应对象
    • 五、银行操作工厂
    • 六、门面类 - 提供统一的接口访问点
    • 七、使用示例
    • 设计说明

Talk is cheap, show me the code.

背景

项目中要用对接 10 家银行的支付接口、余额查询、流水交易结果查询等接口
作者将尝试使用策略模式 + 门面模式设计一下API,增加 API 的易用性

一、定义银行操作的统一接口(策略接口)

// 1. 定义银行操作的统一接口(策略接口)
public interface BankOperations {
    PaymentResult doPayment(PaymentRequest request);
    BalanceResult queryBalance(BalanceRequest request);
    TransactionResult queryTransaction(TransactionRequest request);
}

二、各银行实现类

工商银行

// 2. 各银行实现类
public class ICBCBankOperations implements BankOperations {
    @Override
    public PaymentResult doPayment(PaymentRequest request) {
        // 工商银行支付实现
        return null;
    }

    @Override
    public BalanceResult queryBalance(BalanceRequest request) {
        // 工商银行余额查询实现
        return null;
    }

    @Override
    public TransactionResult queryTransaction(TransactionRequest request) {
        // 工商银行交易查询实现
        return null;
    }
}

农业银行

public class ABCBankOperations implements BankOperations {
    // 农业银行实现...
}

建设银行

public class CCBBankOperations implements BankOperations {
    // 建设银行实现...
}

三、银行类型枚举

// 3. 银行类型枚举
public enum BankType {
    ICBC, ABC, CCB
}

四、统一的请求和响应对象

// 4. 统一的请求和响应对象
@Data
public class PaymentRequest {
    private String accountNo;
    private BigDecimal amount;
    private String currency;
    private String purpose;
    // 其他通用支付参数...
}

@Data
public class PaymentResult {
    private String transactionId;
    private String status;
    private String message;
    // 其他通用返回字段...
}

五、银行操作工厂

// 5. 银行操作工厂
@Component
public class BankOperationsFactory {
    private final Map<BankType, BankOperations> operationsMap = new HashMap<>();

    @Autowired
    public BankOperationsFactory(List<BankOperations> operations) {
        // 初始化银行操作实现映射
        operations.forEach(operation -> {
            if (operation instanceof ICBCBankOperations) {
                operationsMap.put(BankType.ICBC, operation);
            } else if (operation instanceof ABCBankOperations) {
                operationsMap.put(BankType.ABC, operation);
            } else if (operation instanceof CCBBankOperations) {
                operationsMap.put(BankType.CCB, operation);
            }
        });
    }

    public BankOperations getOperation(BankType bankType) {
        return operationsMap.get(bankType);
    }
}

六、门面类 - 提供统一的接口访问点

// 6. 门面类 - 提供统一的接口访问点
@Service
public class BankServiceFacade {
    private final BankOperationsFactory factory;
    
    @Autowired
    public BankServiceFacade(BankOperationsFactory factory) {
        this.factory = factory;
    }

    public PaymentResult doPayment(BankType bankType, PaymentRequest request) {
        try {
            BankOperations operations = factory.getOperation(bankType);
            return operations.doPayment(request);
        } catch (Exception e) {
            log.error("Payment failed", e);
            return PaymentResult.builder()
                    .status("FAILED")
                    .message(e.getMessage())
                    .build();
        }
    }

    public BalanceResult queryBalance(BankType bankType, BalanceRequest request) {
        try {
            BankOperations operations = factory.getOperation(bankType);
            return operations.queryBalance(request);
        } catch (Exception e) {
            log.error("Balance query failed", e);
            return BalanceResult.builder()
                    .status("FAILED")
                    .message(e.getMessage())
                    .build();
        }
    }

    public TransactionResult queryTransaction(BankType bankType, TransactionRequest request) {
        try {
            BankOperations operations = factory.getOperation(bankType);
            return operations.queryTransaction(request);
        } catch (Exception e) {
            log.error("Transaction query failed", e);
            return TransactionResult.builder()
                    .status("FAILED")
                    .message(e.getMessage())
                    .build();
        }
    }
}

七、使用示例

// 7. 使用示例
@Service
public class PaymentService {
    @Autowired
    private BankServiceFacade bankService;

    public void processPayment() {
        PaymentRequest request = new PaymentRequest();
        request.setAccountNo("1234567890");
        request.setAmount(new BigDecimal("100.00"));
        
        // 调用工商银行支付
        PaymentResult result = bankService.doPayment(BankType.ICBC, request);
        
        // 处理支付结果...
    }
}

设计说明

  1. 策略模式

    • BankOperations 接口定义了所有银行操作的统一接口
    • 每个银行都有自己的实现类(ICBCBankOperations, ABCBankOperations, CCBBankOperations)
    • 通过工厂类动态选择具体的实现
  2. 门面模式

    • BankServiceFacade 提供了一个统一的访问点
    • 封装了异常处理和日志记录
    • 简化了客户端的调用方式
  3. 扩展性

    • 添加新银行只需要:
      1. 实现 BankOperations 接口
      2. 在 BankType 中添加新的枚举值
      3. 在工厂类中注册新的实现
  4. 可维护性

    • 每个银行的实现相互独立
    • 共用的代码抽取到基类或工具类
    • 统一的异常处理和日志记录
  5. 使用建议

    • 可以添加配置类管理银行的连接参数
    • 可以使用适配器模式处理不同银行的返回格式
    • 可以添加重试机制和熔断机制
    • 建议添加参数验证和安全检查

这样的设计让代码结构清晰,易于维护和扩展,同时也提供了良好的用户体验。

相关文章:

  • # 线性代数:660习题总结660# 宋浩讲解视频
  • [Lc18_拓扑排序] string+queue+map | 火星字典
  • Stable Diffusion vue本地api接口对接,模型切换, ai功能集成开源项目 ollama-chat-ui-vue
  • 银行的压力测试如何进行?
  • GitHub绑定本地计算机以及仓库创建跟推送指南
  • 深入解析VLAN接口类型与数据处理机制
  • es6的100个问题
  • 无人机,雷达定点飞行时,位置发散,位置很飘,原因分析
  • 合规+增效 正也科技携智能营销产品出席中睿论坛
  • 材质及制作笔记
  • 如何在根据名称或id找到json里的节点以及对应的所有的父节点?
  • 【JavaScript】八、对象
  • mybatis笔记(下)
  • 每日一题之杨辉三角
  • scss基础用法
  • AI×数据治理|百分点科技BD-OS重构数据工程的“基石能力”
  • Linux系统 | 线程的同步与互斥
  • 蓝桥杯 合并数列
  • AI Agent 开发与传统后端开发区别?
  • 项目-苍穹外卖(十六) Apache ECharts+数据统计
  • 第78届戛纳电影节开幕,罗伯特·德尼罗领取终身成就奖
  • 美国4月CPI同比上涨2.3%低于预期,为2021年2月来最小涨幅
  • 学习教育期间违规吃喝,李献林、叶金广等人被通报
  • 秦洪看盘|交易新逻辑,银行股成A股稳定器
  • 学者的“好运气”:读本尼迪克特·安德森《椰壳碗外的人生》
  • 广东韶关一镇干部冲进交通事故火海救人,获授“见义勇为”奖励万元