在软件设计中,我们经常会遇到系统整合的问题:新系统需要与老系统对接,第三方库的接口与我们的期望不匹配,或者不同模块之间的接口标准不一致。适配器模式正是解决这类接口不兼容问题的银弹。
什么是适配器模式?
适配器模式(Adapter Pattern)是一种结构型设计模式,它充当两个不兼容接口之间的桥梁,将一个类的接口转换成客户端期望的另一个接口。就像现实世界中的电源适配器一样,它让美规插头能在中国的插座上使用。
适配器模式的三种角色
-
目标接口(Target):客户端期望的接口
-
适配者(Adaptee):需要被适配的现有接口
-
适配器(Adapter):将适配者接口转换成目标接口
实际案例:支付系统集成
假设我们正在开发一个电商平台,需要集成多种支付方式,但每个支付服务商提供的接口都不相同。
1. 定义统一的支付接口(目标接口)
// 目标接口:我们期望的统一支付接口
interface PaymentProcessor {
fun processPayment(amount: Double, currency: String): PaymentResult
fun refund(transactionId: String): Boolean
fun 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? = null
val 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.name
itemView.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统一成一致的接口
-
🔄 灵活扩展:新增支付方式只需添加新的适配器
-
🧪 易于测试:可以轻松创建模拟适配器进行单元测试
-
🏗️ 结构清晰:代码职责分明,维护性强