适配器模式(Adapter Pattern)是一种结构型设计模式,它允许将一个类(或对象)的接口转换成客户端期望的另一个接口。适配器让那些由于接口不兼容而不能在一起工作的类可以协同工作。
适配器模式使用场景
在以下情况下可以考虑使用适配器模式:
- 接口兼容问题: 系统需要使用现有的类,而这些类的接口不符合系统的需求。
- 提高代码复用性:可以复用一些现有的、功能强大的类,而无需修改其源代码。
- 增强系统灵活性:将客户端代码与具体实现解耦。如果未来需要替换或引入新的被适配者,只需创建一个新的适配器,而无需修改客户端代码。这在集成第三方库或处理遗留代码时尤其有用。
适配器模式的结构
适配器模式包含以下主要角色:
- 目标接口(Target):定义客户端使用的与特定领域相关的接口。
- 适配者(Adaptee):包含一些已有的功能,但其接口与目标接口不兼容。
- 适配器(Adapter):将适配者的接口转换成目标接口,使客户端能够与适配者进行交互。
- 客户端 (Client) :使用目标接口的代码
适配器模式的实现
多种支付方式适配器
在电商系统中,我们经常需要集成多种支付方式(支付宝、微信支付、银联等),每种支付方式的接口都不相同。
1. 目标接口 (Target)
所有支付方式都需要提供一个统一的 pay(amount, orderId) 方法。
1
| adapter.pay(amount, orderId);
|
2. 适配者(Adaptee)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| class AlipayService { makePayment(amount, orderId) { console.log(`支付宝支付: 订单${orderId}, 金额${amount}元`); return { success: true, transactionId: 'alipay_' + Date.now(), message: '支付宝支付成功' }; } }
class WechatPayService { pay(money, orderNumber) { console.log(`微信支付: 订单${orderNumber}, 金额${money}元`); return { status: 'ok', wxTransactionId: 'wx_' + Date.now(), desc: '微信支付完成' }; } }
class UnionPayService { processPayment(orderInfo) { console.log(`银联支付: 订单${orderInfo.id}, 金额${orderInfo.amount}元`); return { code: 200, unionPayId: 'union_' + Date.now(), result: '银联支付成功' }; } }
|
3. 适配器(Adapter)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| class PaymentAdapter { constructor(paymentService, type) { this.paymentService = paymentService; this.type = type; }
pay(amount, orderId) { let result; switch (this.type) { case 'alipay': result = this.paymentService.makePayment(amount, orderId); return { success: result.success, transactionId: result.transactionId, message: result.message }; case 'wechat': result = this.paymentService.pay(amount, orderId); return { success: result.status === 'ok', transactionId: result.wxTransactionId, message: result.desc }; case 'unionpay': result = this.paymentService.processPayment({ id: orderId, amount }); return { success: result.code === 200, transactionId: result.unionPayId, message: result.result }; default: throw new Error('不支持的支付方式'); } } }
|
4. 客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| function processOrder(paymentType, amount, orderId) { let paymentService; let adapter; switch (paymentType) { case 'alipay': paymentService = new AlipayService(); adapter = new PaymentAdapter(paymentService, 'alipay'); break; case 'wechat': paymentService = new WechatPayService(); adapter = new PaymentAdapter(paymentService, 'wechat'); break; case 'unionpay': paymentService = new UnionPayService(); adapter = new PaymentAdapter(paymentService, 'unionpay'); break; } const result = adapter.pay(amount, orderId); console.log('支付结果:', result); return result; }
processOrder('alipay', 100, '1'); processOrder('wechat', 200, '2'); processOrder('unionpay', 300, '3');
|
扩展新支付方式
新增 PayPal 支付时:
- 新建 PaypalService 类;
- 修改 PaymentAdapter 添加 “paypal” 的逻辑;
- 修改 processOrder 添加 “paypal” 分支;
优缺点总结
优点
- 代码复用 :可以复用现有的类,无需修改其源代码
- 解耦 :将客户端代码与具体实现分离
- 灵活性 :可以轻松替换或添加新的适配器
- 符合开闭原则 :对扩展开放,对修改关闭
缺点
- 增加复杂性 :引入了额外的抽象层
- 性能开销 :可能会有轻微的性能损失
- 维护成本 :需要维护适配器代码