适配器模式:让不兼容的接口协同工作
在软件设计中,我们经常会遇到系统整合的问题:新系统需要与老系统对接,第三方库的接口与我们的期望不匹配,或者不同模块之间的接口标准不一致。适配器模式正是解决这类接口不兼容问题的银弹。
什么是适配器模式?
适配器模式(Adapter Pattern)是一种结构型设计模式,它充当两个不兼容接口之间的桥梁,将一个类的接口转换成客户端期望的另一个接口。就像现实世界中的电源适配器一样,它让美规插头能在中国的插座上使用。
适配器模式的三种角色
- 目标接口(Target):客户端期望的接口 
- 适配者(Adaptee):需要被适配的现有接口 
- 适配器(Adapter):将适配者接口转换成目标接口 
实际案例:支付系统集成
假设我们正在开发一个电商平台,需要集成多种支付方式,但每个支付服务商提供的接口都不相同。
1. 定义统一的支付接口(目标接口)
// 目标接口:我们期望的统一支付接口
interface PaymentProcessor {fun processPayment(amount: Double, currency: String): PaymentResultfun refund(transactionId: String): Booleanfun supports(currency: String): Boolean
}data class PaymentResult(val success: Boolean,val transactionId: String? = null,val message: String = ""
)2. 现有的支付服务(需要被适配的类)
// 支付宝SDK提供的类(我们无法修改)
class AlipaySDK {fun pay(amount: Double, currency: String, callback: (Boolean, String) -> Unit) {// 支付宝的异步回调方式Thread.sleep(1000) // 模拟网络请求callback(true, "ALIPAY_${System.currentTimeMillis()}")}fun isCurrencySupported(currency: String): Boolean {return currency in listOf("CNY", "USD", "EUR")}
}// 微信支付SDK
class WechatPaySDK {fun wechatPayment(amount: Double, curr: String): WechatResponse {Thread.sleep(800)return WechatResponse(code = 200,transactionNo = "WECHAT_${System.currentTimeMillis()}",msg = "支付成功")}
}data class WechatResponse(val code: Int, val transactionNo: String, val msg: String)// PayPal SDK(国外支付)
class PayPalService {fun makePayment(amount: Double, currency: String): PaymentOutcome {Thread.sleep(1200)return if (amount > 0) {PaymentOutcome("SUCCESS", "PAYPAL_${System.currentTimeMillis()}")} else {PaymentOutcome("FAILED", null)}}fun processRefund(paymentId: String): Boolean {return paymentId.startsWith("PAYPAL")}
}data class PaymentOutcome(val status: String, val paymentId: String?)3. 实现适配器类
// 支付宝适配器
class AlipayAdapter(private val alipay: AlipaySDK) : PaymentProcessor {override fun processPayment(amount: Double, currency: String): PaymentResult {return try {var result: PaymentResult? = nullval lock = Object()alipay.pay(amount, currency) { success, transactionId ->result = if (success) {PaymentResult(true, transactionId, "支付宝支付成功")} else {PaymentResult(false, message = "支付宝支付失败")}synchronized(lock) { lock.notify() }}synchronized(lock) { lock.wait(5000) } // 等待回调,超时5秒result ?: PaymentResult(false, message = "支付超时")} catch (e: Exception) {PaymentResult(false, message = "支付宝支付异常: ${e.message}")}}override fun refund(transactionId: String): Boolean {// 支付宝退款逻辑(简化)return transactionId.startsWith("ALIPAY")}override fun supports(currency: String): Boolean {return alipay.isCurrencySupported(currency)}
}// 微信支付适配器
class WechatPayAdapter(private val wechatPay: WechatPaySDK) : PaymentProcessor {override fun processPayment(amount: Double, currency: String): PaymentResult {return try {val response = wechatPay.wechatPayment(amount, currency)if (response.code == 200) {PaymentResult(true, response.transactionNo, response.msg)} else {PaymentResult(false, message = "微信支付失败: ${response.msg}")}} catch (e: Exception) {PaymentResult(false, message = "微信支付异常: ${e.message}")}}override fun refund(transactionId: String): Boolean {// 微信退款逻辑return transactionId.startsWith("WECHAT")}override fun supports(currency: String): Boolean {// 微信支付支持常见货币return currency in listOf("CNY", "USD", "HKD")}
}// PayPal适配器
class PayPalAdapter(private val paypal: PayPalService) : PaymentProcessor {override fun processPayment(amount: Double, currency: String): PaymentResult {return try {val outcome = paypal.makePayment(amount, currency)when (outcome.status) {"SUCCESS" -> PaymentResult(true, outcome.paymentId, "PayPal支付成功")else -> PaymentResult(false, message = "PayPal支付失败")}} catch (e: Exception) {PaymentResult(false, message = "PayPal支付异常: ${e.message}")}}override fun refund(transactionId: String): Boolean {return paypal.processRefund(transactionId)}override fun supports(currency: String): Boolean {// PayPal支持全球主要货币return currency in listOf("USD", "EUR", "GBP", "CAD", "AUD", "JPY", "CNY")}
}4. 支付工厂类
// 支付工厂,统一创建适配器
object PaymentProcessorFactory {fun createProcessor(type: PaymentType): PaymentProcessor {return when (type) {PaymentType.ALIPAY -> AlipayAdapter(AlipaySDK())PaymentType.WECHAT -> WechatPayAdapter(WechatPaySDK())PaymentType.PAYPAL -> PayPalAdapter(PayPalService())}}
}enum class PaymentType {ALIPAY, WECHAT, PAYPAL
}5. 客户端使用
// 电商订单处理类
class OrderService {private val paymentProcessors = mutableMapOf<PaymentType, PaymentProcessor>()fun processOrder(order: Order) {println("处理订单: ${order.id}, 金额: ${order.amount} ${order.currency}")val processor = getPaymentProcessor(order.paymentType, order.currency)?: throw IllegalArgumentException("不支持的支付方式或货币")val result = processor.processPayment(order.amount, order.currency)if (result.success) {println("✅ 支付成功! 交易号: ${result.transactionId}")// 更新订单状态updateOrderStatus(order.id, OrderStatus.PAID, result.transactionId)} else {println("❌ 支付失败: ${result.message}")updateOrderStatus(order.id, OrderStatus.FAILED)}}private fun getPaymentProcessor(type: PaymentType, currency: String): PaymentProcessor? {val processor = paymentProcessors.getOrPut(type) {PaymentProcessorFactory.createProcessor(type)}return if (processor.supports(currency)) processor else null}fun refundOrder(order: Order) {order.transactionId?.let { transactionId ->val processor = PaymentProcessorFactory.createProcessor(order.paymentType)val success = processor.refund(transactionId)if (success) {println("✅ 退款成功")updateOrderStatus(order.id, OrderStatus.REFUNDED)} else {println("❌ 退款失败")}}}private fun updateOrderStatus(orderId: String, status: OrderStatus, transactionId: String? = null) {// 实际项目中会更新数据库println("更新订单状态: $orderId -> $status")}
}// 数据类
data class Order(val id: String,val amount: Double,val currency: String,val paymentType: PaymentType,val transactionId: String? = null
)enum class OrderStatus {PENDING, PAID, FAILED, REFUNDED
}6. 测试代码
fun main() {val orderService = OrderService()// 测试不同支付方式val orders = listOf(Order("ORDER_001", 299.0, "CNY", PaymentType.ALIPAY),Order("ORDER_002", 199.0, "USD", PaymentType.PAYPAL),Order("ORDER_003", 159.0, "CNY", PaymentType.WECHAT),Order("ORDER_004", 399.0, "EUR", PaymentType.ALIPAY) // 测试不支持的货币)orders.forEach { order ->println("\n" + "=".repeat(50))try {orderService.processOrder(order)} catch (e: Exception) {println("❌ 订单处理异常: ${e.message}")}Thread.sleep(1000) // 模拟处理间隔}// 测试退款println("\n" + "=".repeat(50))val refundOrder = Order("ORDER_001", 299.0, "CNY", PaymentType.ALIPAY, "ALIPAY_123456")orderService.refundOrder(refundOrder)
}适配器模式的变体
1. 类适配器(通过继承)
// 类适配器(Kotlin 支持多接口继承)
open class LegacyLogger {fun logMessage(level: String, message: String) {println("[$level] $message")}
}interface ModernLogger {fun debug(message: String)fun info(message: String)fun error(message: String)
}// 类适配器通过继承实现
class LoggerAdapter : LegacyLogger(), ModernLogger {override fun debug(message: String) = logMessage("DEBUG", message)override fun info(message: String) = logMessage("INFO", message)override fun error(message: String) = logMessage("ERROR", message)
}2. 对象适配器(通过组合)
// 对象适配器(推荐,符合组合优于继承原则)
class LoggerAdapter(private val legacyLogger: LegacyLogger) : ModernLogger {override fun debug(message: String) = legacyLogger.logMessage("DEBUG", message)override fun info(message: String) = legacyLogger.logMessage("INFO", message)override fun error(message: String) = legacyLogger.logMessage("ERROR", message)
}适配器模式在Android开发中的应用
1. RecyclerView适配器
// 经典的Adapter模式应用
class UserAdapter(private val users: List<User>) : RecyclerView.Adapter<UserAdapter.ViewHolder>() {// 将数据适配为View的展示override fun onBindViewHolder(holder: ViewHolder, position: Int) {val user = users[position]holder.bind(user)}class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {fun bind(user: User) {itemView.usernameText.text = user.nameitemView.emailText.text = user.email// 将数据适配到UI组件}}
}2. 第三方库适配
// 假设我们需要将不同的图片加载库统一接口
interface ImageLoader {fun loadImage(url: String, imageView: ImageView)fun loadImageWithPlaceholder(url: String, imageView: ImageView, placeholder: Int)
}// Glide适配器
class GlideAdapter : ImageLoader {override fun loadImage(url: String, imageView: ImageView) {Glide.with(imageView.context).load(url).into(imageView)}override fun loadImageWithPlaceholder(url: String, imageView: ImageView, placeholder: Int) {Glide.with(imageView.context).load(url).placeholder(placeholder).into(imageView)}
}// Picasso适配器
class PicassoAdapter : ImageLoader {override fun loadImage(url: String, imageView: ImageView) {Picasso.get().load(url).into(imageView)}override fun loadImageWithPlaceholder(url: String, imageView: ImageView, placeholder: Int) {Picasso.get().load(url).placeholder(placeholder).into(imageView)}
}适配器模式的优缺点
✅ 优点
- 单一职责原则:将接口转换代码从业务逻辑中分离 
- 开闭原则:可以引入新适配器而不修改现有代码 
- 解耦合:客户端与具体实现解耦 
- 复用性:可以复用现有的类 
❌ 缺点
- 复杂度增加:需要增加额外的类和接口 
- 过度设计:在简单场景下可能显得繁琐 
适用场景
- 系统集成:整合第三方库或遗留系统 
- 接口标准化:统一多个类似功能的接口 
- 版本兼容:新版本API需要兼容老版本 
- 测试模拟:创建测试替身(Test Double) 
最佳实践
- 优先使用对象适配器:组合优于继承,更灵活 
- 保持适配器简单:只做接口转换,不添加业务逻辑 
- 使用依赖注入:便于测试和替换不同的适配器 
- 适当的命名:如 - XxxAdapter、- XxxWrapper等
总结
适配器模式是解决接口不兼容问题的利器,它就像软件世界中的"万能转接头"。通过本文的支付系统案例,我们可以看到适配器模式在实际项目中的强大作用:
- 🎯 统一接口:将不同的支付SDK统一成一致的接口 
- 🔄 灵活扩展:新增支付方式只需添加新的适配器 
- 🧪 易于测试:可以轻松创建模拟适配器进行单元测试 
- 🏗️ 结构清晰:代码职责分明,维护性强 
