在 Spring Boot 中使用适配器模式实现支付网关的统一接口
引言
在许多电子商务系统中,集成多个支付网关是常见的需求。不同的支付网关有着不同的接口和实现细节。适配器模式可以帮助我们以一种灵活的方式实现这些不同的支付网关接口。
适配器模式简介
适配器模式将一个类的接口转换为客户期望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
示例
假设我们有一个电商平台,需要支持多种支付网关,包括:
- PayPal支付网关
- Stripe支付网关
- Alipay支付网关
步骤
-
定义目标接口 - 首先定义一个目标接口,声明所有支持的支付网关共有的方法。
java深色版本
1public interface PaymentGateway { 2 void processPayment(PaymentRequest request); 3} -
实现具体的支付网关类 - 接下来,为每种支付网关实现适配器。
-
PayPal支付网关适配器
java深色版本
1import org.springframework.stereotype.Component; 2 3@Component 4public class PayPalPaymentGatewayAdapter implements PaymentGateway { 5 private final PayPalApi paypalApi; 6 7 public PayPalPaymentGatewayAdapter(PayPalApi paypalApi) { 8 this.paypalApi = paypalApi; 9 } 10 11 @Override 12 public void processPayment(PaymentRequest request) { 13 PayPalPaymentRequest paypalRequest = new PayPalPaymentRequest(request); 14 paypalApi.processPayment(paypalRequest); 15 } 16} -
Stripe支付网关适配器
java深色版本
1import org.springframework.stereotype.Component; 2 3@Component 4public class StripePaymentGatewayAdapter implements PaymentGateway { 5 private final StripeApi stripeApi; 6 7 public StripePaymentGatewayAdapter(StripeApi stripeApi) { 8 this.stripeApi = stripeApi; 9 } 10 11 @Override 12 public void processPayment(PaymentRequest request) { 13 StripePaymentRequest stripeRequest = new StripePaymentRequest(request); 14 stripeApi.processPayment(stripeRequest); 15 } 16} -
Alipay支付网关适配器
java深色版本
1import org.springframework.stereotype.Component; 2 3@Component 4public class AlipayPaymentGatewayAdapter implements PaymentGateway { 5 private final AlipayApi alipayApi; 6 7 public AlipayPaymentGatewayAdapter(AlipayApi alipayApi) { 8 this.alipayApi = alipayApi; 9 } 10 11 @Override 12 public void processPayment(PaymentRequest request) { 13 AlipayPaymentRequest alipayRequest = new AlipayPaymentRequest(request); 14 alipayApi.processPayment(alipayRequest); 15 } 16}
-
-
定义具体的支付网关 API 接口 - 为每个支付网关定义一个具体的 API 接口。
-
PayPal API 接口
java深色版本
1public interface PayPalApi { 2 void processPayment(PayPalPaymentRequest request); 3} -
Stripe API 接口
java深色版本
1public interface StripeApi { 2 void processPayment(StripePaymentRequest request); 3} -
Alipay API 接口
java深色版本
1public interface AlipayApi { 2 void processPayment(AlipayPaymentRequest request); 3}
-
-
实现具体的支付网关 API 类 - 接下来,为每个支付网关实现具体的 API 类。
-
PayPal API 类
java深色版本
1import org.springframework.stereotype.Component; 2 3@Component 4public class PayPalApiImpl implements PayPalApi { 5 @Override 6 public void processPayment(PayPalPaymentRequest request) { 7 System.out.println("Processing payment via PayPal: " + request.getAmount()); 8 } 9} -
Stripe API 类
java深色版本
1import org.springframework.stereotype.Component; 2 3@Component 4public class StripeApiImpl implements StripeApi { 5 @Override 6 public void processPayment(StripePaymentRequest request) { 7 System.out.println("Processing payment via Stripe: " + request.getAmount()); 8 } 9} -
Alipay API 类
java深色版本
1import org.springframework.stereotype.Component; 2 3@Component 4public class AlipayApiImpl implements AlipayApi { 5 @Override 6 public void processPayment(AlipayPaymentRequest request) { 7 System.out.println("Processing payment via Alipay: " + request.getAmount()); 8 } 9}
-
-
定义支付请求类 - 定义一个支付请求类,用于封装支付请求的必要信息。
java深色版本
1public class PaymentRequest { 2 private String paymentMethod; 3 private double amount; 4 5 public PaymentRequest(String paymentMethod, double amount) { 6 this.paymentMethod = paymentMethod; 7 this.amount = amount; 8 } 9 10 public String getPaymentMethod() { 11 return paymentMethod; 12 } 13 14 public double getAmount() { 15 return amount; 16 } 17} -
定义具体的支付请求类 - 为每个支付网关定义一个具体的支付请求类。
-
PayPal支付请求
java深色版本
1public class PayPalPaymentRequest { 2 private final PaymentRequest request; 3 4 public PayPalPaymentRequest(PaymentRequest request) { 5 this.request = request; 6 } 7 8 public String getPaymentMethod() { 9 return request.getPaymentMethod(); 10 } 11 12 public double getAmount() { 13 return request.getAmount(); 14 } 15} -
Stripe支付请求
java深色版本
1public class StripePaymentRequest { 2 private final PaymentRequest request; 3 4 public StripePaymentRequest(PaymentRequest request) { 5 this.request = request; 6 } 7 8 public String getPaymentMethod() { 9 return request.getPaymentMethod(); 10 } 11 12 public double getAmount() { 13 return request.getAmount(); 14 } 15} -
Alipay支付请求
java深色版本
1public class AlipayPaymentRequest { 2 private final PaymentRequest request; 3 4 public AlipayPaymentRequest(PaymentRequest request) { 5 this.request = request; 6 } 7 8 public String getPaymentMethod() { 9 return request.getPaymentMethod(); 10 } 11 12 public double getAmount() { 13 return request.getAmount(); 14 } 15}
-
-
使用适配器 - 最后,在我们的业务逻辑中,根据需要选择并使用相应的适配器。
java深色版本
1import org.springframework.beans.factory.annotation.Autowired; 2import org.springframework.stereotype.Service; 3 4@Service 5public class PaymentService { 6 7 private final Map<String, PaymentGateway> paymentGateways; 8 9 @Autowired 10 public PaymentService(Map<String, PaymentGateway> paymentGateways) { 11 this.paymentGateways = paymentGateways; 12 } 13 14 public void processPayment(PaymentRequest request) { 15 PaymentGateway paymentGateway = paymentGateways.get(request.getPaymentMethod()); 16 if (paymentGateway != null) { 17 paymentGateway.processPayment(request); 18 } else { 19 throw new IllegalArgumentException("Unsupported payment method: " + request.getPaymentMethod()); 20 } 21 } 22} -
控制器 - 我们还需要一个控制器来测试这个逻辑。
java深色版本
1import org.springframework.beans.factory.annotation.Autowired; 2import org.springframework.web.bind.annotation.GetMapping; 3import org.springframework.web.bind.annotation.RequestMapping; 4import org.springframework.web.bind.annotation.RequestParam; 5import org.springframework.web.bind.annotation.RestController; 6 7@RestController 8@RequestMapping("/payments") 9public class PaymentController { 10 11 private final PaymentService paymentService; 12 13 @Autowired 14 public PaymentController(PaymentService paymentService) { 15 this.paymentService = paymentService; 16 } 17 18 @GetMapping("/process") 19 public String processPayment(@RequestParam("method") String method, 20 @RequestParam("amount") double amount) { 21 PaymentRequest request = new PaymentRequest(method, amount); 22 paymentService.processPayment(request); 23 return "Payment processed successfully."; 24 } 25} -
测试 - 最后,我们可以通过发送 HTTP 请求来测试不同的支付网关。
bash深色版本
1curl 'http://localhost:8080/payments/process?method=paypal&amount=100' 2curl 'http://localhost:8080/payments/process?method=stripe&amount=150' 3curl 'http://localhost:8080/payments/process?method=alipay&amount=200'
结论
通过使用适配器模式,我们可以在运行时灵活地选择不同的支付网关,并使用统一的接口与之交互。这种方式不仅提高了代码的可读性和可维护性,还使得扩展新的支付网关变得非常简单。在 Spring Boot 中,依赖注入机制进一步简化了适配器模式的实现过程。
相关文章:
在 Spring Boot 中使用适配器模式实现支付网关的统一接口
引言 在许多电子商务系统中,集成多个支付网关是常见的需求。不同的支付网关有着不同的接口和实现细节。适配器模式可以帮助我们以一种灵活的方式实现这些不同的支付网关接口。 适配器模式简介 适配器模式将一个类的接口转换为客户期望的另一个接口。适配器模式使…...
【书生·浦语大模型实战营】第三期 入门岛作业
入门岛作业 Linux闯关任务:完成 SSH 连接与端口映射并运行 hello_world.py。配置vscode作业内容 可选任务1:将Linux基础命令在开发机上完成一遍作业内容 可选任务 2:使用 VSCODE 远程连接开发机并创建一个conda环境作业内容 可选任务 3&#…...
Redis的String类型常用命令总结
1. set 设置一个键的值。 set key value示例: set username "alice"2. get 获取一个键的值。 get key示例: get username3. getset 设置键的值,并返回键的旧值。 getset key value示例: getset username "…...
河南萌新联赛2024第(四)场:河南理工大学
A 思路: B 思路:有一种贪心的写法,将整个数组排序以后比较两个相邻数的同或值,取 m a x max max,不会证明 int th(int x, int y, int z) {int res 0;for (int i z - 1; i > 0; i --) {int dx (x >> i &…...
Linux中临时使用账号提权进行业务操作
普通账号提权 su:永久提权 Switching users with su sudo:临时提权 Running commands as root with sudo 1)su切换账号 需要对方的密码 示例:切换到超级管理员 su - root 建议用-这个 su root 普通用户需要执行特殊指令&…...
lwip 3. 网线拔掉后 lwip_recvfrom不能返回
当网线被拔掉后,LWIP的lwip_recvfrom函数无法返回,这通常意味着网络连接已经断开,而LWIP没有自动检测到这种断开并进行相应的处理。具体卡在这个地方: ret xQueueReceive(mbox->mbx, &(*msg), portMAX_DELAY); //具…...
Linux环境安装Docker Engine
Docker是一个开源的应用容器引擎,由Go语言开发,基于Linux内核技术。Docker通过将应用及其依赖打包到可移植的容器中,实现了应用的快速部署和高效管理。Docker容器具有轻量级、快速启动、可移植性强等特点,能够显著提升资源利用率和…...
大厂面试题分享
大厂面试题分享 Redis持久化方式AOF优缺点RDB优缺点 如何保证Redis和Myql的一致性索引下推输入url到浏览器发生了什么ReentranLock底层原理SpringBoot 的启动流程 Redis持久化方式 Redis提供了两种主要的持久化机制,分别是AOF(Append-Only File…...
FPGA面试问题整理
1. 逻辑设计中竞争与冒险概念,如何识别和消除? 竞争:在组合逻辑电路中,信号经过多条路径到达输出端,每条路径经过的逻辑门不同存在时差,在信号变化的瞬间存在先后顺序。这种现象叫竞争。 冒险:由…...
3Done学习笔记
一、基本操作 1、旋转视角 使用左下角立方体选择; 右键可以拖动视角; 中间滑轮按住拖动整个舞台界面。 2、平移和旋转 右键选择移动,有两种方式。 第一种选择起始点,按照起始点位置移动到终止点(边、角、中心点…...
AI学习指南深度学习篇-卷积层详解
AI学习指南深度学习篇-卷积层详解 一、引言 随着人工智能技术的不断发展,深度学习作为人工智能领域的热门分支之一,正在逐渐成为各个领域的核心技术。而在深度学习中,卷积神经网络(Convolutional Neural Network,CNN…...
2024年TI杯E题-三子棋游戏装置方案分享-jdk123团队-第二弹 手搓机械臂
第一弹赛题的选择与前期方案的准备 opencv调用摄像头bug的解决 机械臂的组装 采用三个舵机,组成一个三自由度的机械臂。 并且利用电磁吸盘的方式,完成对棋子的抓取工作,后面的事实证明,在预算不足的情况下,队友手搓…...
如何在Java、C、Ruby语言中使用Newscatcher API
Newscatcher 世界实时新闻聚合API 一款强大的数据服务工具,它通过先进的网络爬虫技术,实时从全球超过70,000个新闻源聚合新闻内容。这个API能够提供全面、多角度的新闻报道,包括但不限于标题、作者、发布日期、全文内容以及媒体资源链接。它使…...
集合: Collection的成员方法和相关实现类
Collection: - List(有序【指的是存储和取出的顺序是一致的】且可以发生重复,且有索引的概念) - ArrayList: 底层数据结构是数组,查询快,增删慢,线程不安全的,效率高。 - …...
过滤器与监听器:深入了解 Java Web 开发中的核心概念
在 Java Web 开发中,过滤器(Filter)和监听器(Listener)是两个重要的组件,它们帮助开发者在请求处理的各个阶段进行预处理和后处理。这篇博客将深入探讨这两个概念,并展示它们如何在实际应用中发…...
【Linux学习】动静态库从原理到制作
🍑个人主页:Jupiter. 🚀 所属专栏:Linux从入门到进阶 欢迎大家点赞收藏评论😊 目录 🍑动静态库🐟动静态库的制作与使用🚀生成静态库🔒生成动态库 🦌动态库的查…...
WPF篇(10)-Label标签+TextBlock文字块+TextBox文本框+RichTextBox富文本框
Label标签 Label控件继承于ContentControl控件,它是一个文本标签,如果您想修改它的标签内容,请设置Content属性。我们曾提过ContentControl的Content属性是object类型,意味着Label的Content也是可以设置为任意的引用类型的。 案…...
JavaFX对话框控件-ChoiceDialog
JavaFX对话框控件-ChoiceDialog 常用属性titlecontentTextinitOwnergraphicheaderTextdefaultValuechoicesdialogPane 常用事件显示事件setOnShowing显示事件setOnShown弹框按钮点击 综合案例自定义下拉框内容 与Alert大部分功能类似按钮不可以自定义多一个下拉框 常用属性 …...
一文了解BTC中的二层协议中Nervos network,CKB,RGB++,UTXO stack 之间的关系
注:该内容不构成投资建议,有些内容摘抄其他地方,如侵权,请联系删除。 Nervos network Nervos Network 是一个开源的区块链生态项目,该项目提供一套解决方案来应对区块链扩展性和互操作性的问题。 Nervos Network 成立…...
Oracle(47)如何创建和使用集合?
在PL/SQL中,集合(Collection)是一种复合数据类型,用于存储一组相关的数据项。集合主要有三种类型:关联数组(Associative Arrays)、嵌套表(Nested Tables)和可变数组&…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...
