Skip to content

适配器模式详解:概念、实现与应用

引言

适配器模式是一种结构型设计模式,它允许不兼容的接口协同工作。适配器模式将一个类的接口转换成客户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的类可以一起工作。

什么是适配器模式?

适配器模式是一种结构型设计模式,它能让接口不兼容的对象能够相互合作。适配器模式充当两个不同接口之间的桥梁,将一个接口转换成另一个接口,使得原本由于接口不兼容而不能一起工作的类可以一起工作。

核心思想

适配器模式的核心思想是:

  1. 接口转换:将一个接口转换成另一个接口
  2. 兼容性解决:解决接口不兼容的问题
  3. 复用现有代码:复用现有的类而不修改其源代码

为什么需要适配器模式?

在许多情况下,我们需要让不兼容的接口协同工作:

1. 集成第三方库

当需要集成第三方库但其接口与现有系统不兼容时:

  • 第三方库使用不同的接口规范
  • 需要将第三方库适配到现有系统中
  • 避免修改现有系统的代码

2. 系统重构

当重构系统但需要保持向后兼容时:

  • 保留旧接口以保持兼容性
  • 提供新接口以支持新功能
  • 逐步迁移现有代码

3. 多种实现的统一

当需要统一多种不同实现的接口时:

  • 不同的数据库驱动程序
  • 不同的消息队列实现
  • 不同的支付网关接口

适配器模式的基本实现

让我们从一个简单的适配器模式实现开始:

javascript
// 目标接口(客户端期望的接口)
class Target {
  request() {
    return '目标接口的默认行为';
  }
}

// 被适配者(不兼容的现有类)
class Adaptee {
  specificRequest() {
    return '被适配者的特殊行为';
  }
}

// 适配器
class Adapter extends Target {
  constructor(adaptee) {
    super();
    this.adaptee = adaptee;
  }
  
  request() {
    const result = this.adaptee.specificRequest();
    return `适配器: 转换 "${result}" 为目标接口格式`;
  }
}

// 客户端代码
function clientCode(target) {
  console.log(target.request());
}

console.log('客户端:我可以很好地处理目标对象:');
const target = new Target();
clientCode(target);

console.log('');

console.log('客户端:被适配者有一个奇怪的接口,我不理解:');
const adaptee = new Adaptee();
console.log(`被适配者: ${adaptee.specificRequest()}`);

console.log('');

console.log('客户端:但是可以通过适配器来处理它:');
const adapter = new Adapter(adaptee);
clientCode(adapter);

实现要点分析

  1. 目标接口:客户端期望的接口
  2. 被适配者:需要适配的现有类
  3. 适配器:实现目标接口并包装被适配者
  4. 客户端:通过目标接口与适配器交互

适配器模式的实际应用场景

1. 支付网关适配器

在电商系统中,适配器模式非常适合用于统一不同支付网关的接口:

javascript
// 支付接口(目标接口)
class PaymentProcessor {
  processPayment(amount, currency) {
    throw new Error('必须实现 processPayment 方法');
  }
  
  refundPayment(transactionId, amount) {
    throw new Error('必须实现 refundPayment 方法');
  }
  
  getTransactionStatus(transactionId) {
    throw new Error('必须实现 getTransactionStatus 方法');
  }
}

// 支付宝支付(被适配者)
class Alipay {
  sendPayment(amount, currency) {
    return {
      success: true,
      transactionId: `alipay_${Date.now()}`,
      message: `支付宝支付 ${amount} ${currency} 成功`
    };
  }
  
  sendRefund(transactionId, amount) {
    return {
      success: true,
      refundId: `refund_${Date.now()}`,
      message: `支付宝退款 ${amount} 成功`
    };
  }
  
  checkOrderStatus(orderId) {
    return {
      status: 'completed',
      message: `订单 ${orderId} 已完成`
    };
  }
}

// 微信支付(被适配者)
class WeChatPay {
  makePayment(amount, currency) {
    return {
      result: 'SUCCESS',
      out_trade_no: `wechat_${Date.now()}`,
      return_msg: `微信支付 ${amount} ${currency} 成功`
    };
  }
  
  refund(transationId, totalFee, refundFee) {
    return {
      result_code: 'SUCCESS',
      refund_id: `refund_${Date.now()}`,
      return_msg: `微信退款 ${refundFee} 成功`
    };
  }
  
  queryOrder(outTradeNo) {
    return {
      trade_state: 'SUCCESS',
      trade_state_desc: `订单 ${outTradeNo} 已支付`
    };
  }
}

// PayPal 支付(被适配者)
class PayPal {
  createPayment(amount, currencyCode) {
    return {
      id: `paypal_${Date.now()}`,
      state: 'approved',
      message: `PayPal 支付 ${amount} ${currencyCode} 成功`
    };
  }
  
  refundPayment(saleId, amount) {
    return {
      id: `paypal_refund_${Date.now()}`,
      state: 'completed',
      message: `PayPal 退款 $${amount} 成功`
    };
  }
  
  getPaymentDetails(paymentId) {
    return {
      state: 'approved',
      message: `支付 ${paymentId} 状态正常`
    };
  }
}

// 支付宝适配器
class AlipayAdapter extends PaymentProcessor {
  constructor(alipay) {
    super();
    this.alipay = alipay;
  }
  
  processPayment(amount, currency) {
    const result = this.alipay.sendPayment(amount, currency);
    return {
      success: result.success,
      transactionId: result.transactionId,
      message: result.message
    };
  }
  
  refundPayment(transactionId, amount) {
    const result = this.alipay.sendRefund(transactionId, amount);
    return {
      success: result.success,
      refundId: result.refundId,
      message: result.message
    };
  }
  
  getTransactionStatus(transactionId) {
    const result = this.alipay.checkOrderStatus(transactionId);
    return {
      status: result.status,
      message: result.message
    };
  }
}

// 微信支付适配器
class WeChatPayAdapter extends PaymentProcessor {
  constructor(wechatPay) {
    super();
    this.wechatPay = wechatPay;
  }
  
  processPayment(amount, currency) {
    const result = this.wechatPay.makePayment(amount, currency);
    return {
      success: result.result === 'SUCCESS',
      transactionId: result.out_trade_no,
      message: result.return_msg
    };
  }
  
  refundPayment(transactionId, amount) {
    // 微信支付需要总费用和退款费用
    const result = this.wechatPay.refund(transactionId, amount, amount);
    return {
      success: result.result_code === 'SUCCESS',
      refundId: result.refund_id,
      message: result.return_msg
    };
  }
  
  getTransactionStatus(transactionId) {
    const result = this.wechatPay.queryOrder(transactionId);
    return {
      status: result.trade_state,
      message: result.trade_state_desc
    };
  }
}

// PayPal 适配器
class PayPalAdapter extends PaymentProcessor {
  constructor(paypal) {
    super();
    this.paypal = paypal;
  }
  
  processPayment(amount, currency) {
    const result = this.paypal.createPayment(amount, currency);
    return {
      success: result.state === 'approved',
      transactionId: result.id,
      message: result.message
    };
  }
  
  refundPayment(transactionId, amount) {
    const result = this.paypal.refundPayment(transactionId, amount);
    return {
      success: result.state === 'completed',
      refundId: result.id,
      message: result.message
    };
  }
  
  getTransactionStatus(transactionId) {
    const result = this.paypal.getPaymentDetails(transactionId);
    return {
      status: result.state,
      message: result.message
    };
  }
}

// 支付服务管理器
class PaymentService {
  constructor() {
    this.processors = new Map();
  }
  
  registerProcessor(name, processor) {
    this.processors.set(name, processor);
  }
  
  processPayment(processorName, amount, currency) {
    const processor = this.processors.get(processorName);
    if (!processor) {
      throw new Error(`未找到支付处理器: ${processorName}`);
    }
    
    try {
      const result = processor.processPayment(amount, currency);
      console.log(`支付结果: ${result.message}`);
      return result;
    } catch (error) {
      console.error(`支付失败: ${error.message}`);
      return { success: false, message: error.message };
    }
  }
  
  refundPayment(processorName, transactionId, amount) {
    const processor = this.processors.get(processorName);
    if (!processor) {
      throw new Error(`未找到支付处理器: ${processorName}`);
    }
    
    try {
      const result = processor.refundPayment(transactionId, amount);
      console.log(`退款结果: ${result.message}`);
      return result;
    } catch (error) {
      console.error(`退款失败: ${error.message}`);
      return { success: false, message: error.message };
    }
  }
  
  getTransactionStatus(processorName, transactionId) {
    const processor = this.processors.get(processorName);
    if (!processor) {
      throw new Error(`未找到支付处理器: ${processorName}`);
    }
    
    try {
      const result = processor.getTransactionStatus(transactionId);
      console.log(`交易状态: ${result.message}`);
      return result;
    } catch (error) {
      console.error(`查询状态失败: ${error.message}`);
      return { status: 'error', message: error.message };
    }
  }
}

// 使用示例
function paymentExample() {
  const paymentService = new PaymentService();
  
  // 注册支付处理器
  paymentService.registerProcessor('alipay', new AlipayAdapter(new Alipay()));
  paymentService.registerProcessor('wechat', new WeChatPayAdapter(new WeChatPay()));
  paymentService.registerProcessor('paypal', new PayPalAdapter(new PayPal()));
  
  // 使用支付宝支付
  console.log('=== 支付宝支付 ===');
  const alipayResult = paymentService.processPayment('alipay', 100, 'CNY');
  if (alipayResult.success) {
    paymentService.getTransactionStatus('alipay', alipayResult.transactionId);
    paymentService.refundPayment('alipay', alipayResult.transactionId, 50);
  }
  
  console.log('');
  
  // 使用微信支付
  console.log('=== 微信支付 ===');
  const wechatResult = paymentService.processPayment('wechat', 200, 'CNY');
  if (wechatResult.success) {
    paymentService.getTransactionStatus('wechat', wechatResult.transactionId);
    paymentService.refundPayment('wechat', wechatResult.transactionId, 100);
  }
  
  console.log('');
  
  // 使用 PayPal 支付
  console.log('=== PayPal 支付 ===');
  const paypalResult = paymentService.processPayment('paypal', 50, 'USD');
  if (paypalResult.success) {
    paymentService.getTransactionStatus('paypal', paypalResult.transactionId);
    paymentService.refundPayment('paypal', paypalResult.transactionId, 25);
  }
}

paymentExample();

2. 数据库驱动适配器

在数据库访问层中,适配器模式非常适合用于统一不同数据库的接口:

javascript
// 数据库接口(目标接口)
class Database {
  connect() {
    throw new Error('必须实现 connect 方法');
  }
  
  query(sql, params = []) {
    throw new Error('必须实现 query 方法');
  }
  
  execute(sql, params = []) {
    throw new Error('必须实现 execute 方法');
  }
  
  close() {
    throw new Error('必须实现 close 方法');
  }
}

// MySQL 驱动(被适配者)
class MySQLDriver {
  constructor(options) {
    this.host = options.host;
    this.port = options.port;
    this.user = options.user;
    this.password = options.password;
    this.database = options.database;
    this.connected = false;
  }
  
  createConnection() {
    console.log(`MySQL: 连接到 ${this.host}:${this.port}`);
    this.connected = true;
    return { connectionId: 'mysql_conn_1' };
  }
  
  executeQuery(query, values) {
    if (!this.connected) {
      throw new Error('MySQL: 未连接到数据库');
    }
    
    console.log(`MySQL: 执行查询 "${query}" with values:`, values);
    return {
      rows: [
        { id: 1, name: '用户1', email: 'user1@example.com' },
        { id: 2, name: '用户2', email: 'user2@example.com' }
      ],
      rowCount: 2
    };
  }
  
  executeUpdate(sql, values) {
    if (!this.connected) {
      throw new Error('MySQL: 未连接到数据库');
    }
    
    console.log(`MySQL: 执行更新 "${sql}" with values:`, values);
    return { affectedRows: 1, insertId: 3 };
  }
  
  endConnection() {
    console.log('MySQL: 关闭连接');
    this.connected = false;
  }
}

// PostgreSQL 驱动(被适配者)
class PostgreSQLDriver {
  constructor(config) {
    this.host = config.host;
    this.port = config.port;
    this.username = config.username;
    this.password = config.password;
    this.dbname = config.dbname;
    this.client = null;
  }
  
  connect() {
    console.log(`PostgreSQL: 连接到 ${this.host}:${this.port}`);
    this.client = { id: 'pg_client_1' };
    return this.client;
  }
  
  queryDatabase(text, parameters) {
    if (!this.client) {
      throw new Error('PostgreSQL: 未连接到数据库');
    }
    
    console.log(`PostgreSQL: 执行查询 "${text}" with parameters:`, parameters);
    return {
      rows: [
        { id: 1, name: '用户A', email: 'userA@example.com' },
        { id: 2, name: '用户B', email: 'userB@example.com' }
      ],
      rowCount: 2
    };
  }
  
  executeSQL(text, parameters) {
    if (!this.client) {
      throw new Error('PostgreSQL: 未连接到数据库');
    }
    
    console.log(`PostgreSQL: 执行更新 "${text}" with parameters:`, parameters);
    return { rowCount: 1 };
  }
  
  disconnect() {
    console.log('PostgreSQL: 关闭连接');
    this.client = null;
  }
}

// MongoDB 驱动(被适配者)
class MongoDBDriver {
  constructor(url, options) {
    this.url = url;
    this.options = options;
    this.client = null;
    this.db = null;
  }
  
  connectToMongo() {
    console.log(`MongoDB: 连接到 ${this.url}`);
    this.client = { id: 'mongo_client_1' };
    this.db = { name: 'testdb' };
    return this.client;
  }
  
  findDocuments(collection, query, options) {
    if (!this.client) {
      throw new Error('MongoDB: 未连接到数据库');
    }
    
    console.log(`MongoDB: 在集合 ${collection} 中查找文档,查询:`, query, '选项:', options);
    return [
      { _id: '1', name: '文档1', email: 'doc1@example.com' },
      { _id: '2', name: '文档2', email: 'doc2@example.com' },
    ];
  }
  
  updateDocuments(collection, filter, update, options) {
    if (!this.client) {
      throw new Error('MongoDB: 未连接到数据库');
    }
    
    console.log(`MongoDB: 更新集合 ${collection} 中的文档,过滤器:`, filter, '更新:', update);
    return { modifiedCount: 1, matchedCount: 1 };
  }
  
  closeConnection() {
    console.log('MongoDB: 关闭连接');
    this.client = null;
    this.db = null;
  }
}

// MySQL 适配器
class MySQLAdapter extends Database {
  constructor(options) {
    super();
    this.driver = new MySQLDriver(options);
  }
  
  connect() {
    return this.driver.createConnection();
  }
  
  query(sql, params = []) {
    return this.driver.executeQuery(sql, params);
  }
  
  execute(sql, params = []) {
    return this.driver.executeUpdate(sql, params);
  }
  
  close() {
    this.driver.endConnection();
  }
}

// PostgreSQL 适配器
class PostgreSQLAdapter extends Database {
  constructor(config) {
    super();
    this.driver = new PostgreSQLDriver(config);
  }
  
  connect() {
    return this.driver.connect();
  }
  
  query(sql, params = []) {
    return this.driver.queryDatabase(sql, params);
  }
  
  execute(sql, params = []) {
    return this.driver.executeSQL(sql, params);
  }
  
  close() {
    this.driver.disconnect();
  }
}

// MongoDB 适配器
class MongoDBAdapter extends Database {
  constructor(url, options) {
    super();
    this.driver = new MongoDBDriver(url, options);
  }
  
  connect() {
    return this.driver.connectToMongo();
  }
  
  query(sql, params = []) {
    // 将 SQL 查询转换为 MongoDB 查询
    const collection = sql.match(/FROM\s+(\w+)/i)?.[1] || 'default';
    const query = params.length > 0 ? { _id: params[0] } : {};
    return this.driver.findDocuments(collection, query, {});
  }
  
  execute(sql, params = []) {
    // 将 SQL 更新转换为 MongoDB 更新
    const collection = sql.match(/UPDATE\s+(\w+)/i)?.[1] || 'default';
    const filter = params.length > 1 ? { _id: params[0] } : {};
    const update = params.length > 1 ? { $set: params[1] } : {};
    return this.driver.updateDocuments(collection, filter, update, {});
  }
  
  close() {
    this.driver.closeConnection();
  }
}

// 数据库管理器
class DatabaseManager {
  constructor() {
    this.connections = new Map();
  }
  
  connect(dbType, config) {
    let database;
    
    switch (dbType) {
      case 'mysql':
        database = new MySQLAdapter(config);
        break;
      case 'postgresql':
        database = new PostgreSQLAdapter(config);
        break;
      case 'mongodb':
        database = new MongoDBAdapter(config.url, config.options);
        break;
      default:
        throw new Error(`不支持的数据库类型: ${dbType}`);
    }
    
    database.connect();
    this.connections.set(dbType, database);
    return database;
  }
  
  query(dbType, sql, params = []) {
    const database = this.connections.get(dbType);
    if (!database) {
      throw new Error(`未找到数据库连接: ${dbType}`);
    }
    
    return database.query(sql, params);
  }
  
  execute(dbType, sql, params = []) {
    const database = this.connections.get(dbType);
    if (!database) {
      throw new Error(`未找到数据库连接: ${dbType}`);
    }
    
    return database.execute(sql, params);
  }
  
  close(dbType) {
    const database = this.connections.get(dbType);
    if (database) {
      database.close();
      this.connections.delete(dbType);
    }
  }
  
  closeAll() {
    for (const [dbType, database] of this.connections) {
      try {
        database.close();
      } catch (error) {
        console.error(`关闭 ${dbType} 连接时出错:`, error.message);
      }
    }
    this.connections.clear();
  }
}

// 使用示例
function databaseExample() {
  const dbManager = new DatabaseManager();
  
  // 连接 MySQL
  console.log('=== 连接 MySQL ===');
  const mysqlConfig = {
    host: 'localhost',
    port: 3306,
    user: 'root',
    password: 'password',
    database: 'testdb'
  };
  
  try {
    dbManager.connect('mysql', mysqlConfig);
    const mysqlUsers = dbManager.query('mysql', 'SELECT * FROM users WHERE id = ?', [1]);
    console.log('MySQL 查询结果:', mysqlUsers);
    
    const mysqlUpdate = dbManager.execute('mysql', 'UPDATE users SET name = ? WHERE id = ?', ['新名字', 1]);
    console.log('MySQL 更新结果:', mysqlUpdate);
  } catch (error) {
    console.error('MySQL 操作失败:', error.message);
  }
  
  console.log('');
  
  // 连接 PostgreSQL
  console.log('=== 连接 PostgreSQL ===');
  const pgConfig = {
    host: 'localhost',
    port: 5432,
    username: 'postgres',
    password: 'password',
    dbname: 'testdb'
  };
  
  try {
    dbManager.connect('postgresql', pgConfig);
    const pgUsers = dbManager.query('postgresql', 'SELECT * FROM users WHERE id = $1', [1]);
    console.log('PostgreSQL 查询结果:', pgUsers);
    
    const pgUpdate = dbManager.execute('postgresql', 'UPDATE users SET name = $1 WHERE id = $2', ['新名字', 1]);
    console.log('PostgreSQL 更新结果:', pgUpdate);
  } catch (error) {
    console.error('PostgreSQL 操作失败:', error.message);
  }
  
  console.log('');
  
  // 连接 MongoDB
  console.log('=== 连接 MongoDB ===');
  const mongoConfig = {
    url: 'mongodb://localhost:27017',
    options: { useNewUrlParser: true }
  };
  
  try {
    dbManager.connect('mongodb', mongoConfig);
    const mongoDocs = dbManager.query('mongodb', 'SELECT * FROM users', ['1']);
    console.log('MongoDB 查询结果:', mongoDocs);
    
    const mongoUpdate = dbManager.execute('mongodb', 'UPDATE users', ['1', { name: '新名字' }]);
    console.log('MongoDB 更新结果:', mongoUpdate);
  } catch (error) {
    console.error('MongoDB 操作失败:', error.message);
  }
  
  // 关闭所有连接
  console.log('');
  console.log('=== 关闭所有连接 ===');
  dbManager.closeAll();
}

databaseExample();

3. API 客户端适配器

在微服务架构中,适配器模式非常适合用于统一不同服务的 API 接口:

javascript
// API 客户端接口(目标接口)
class APIClient {
  get(endpoint, params = {}) {
    throw new Error('必须实现 get 方法');
  }
  
  post(endpoint, data = {}) {
    throw new Error('必须实现 post 方法');
  }
  
  put(endpoint, data = {}) {
    throw new Error('必须实现 put 方法');
  }
  
  delete(endpoint) {
    throw new Error('必须实现 delete 方法');
  }
  
  setAuthToken(token) {
    throw new Error('必须实现 setAuthToken 方法');
  }
}

// REST API 客户端(被适配者)
class RESTClient {
  constructor(baseUrl) {
    this.baseUrl = baseUrl;
    this.headers = {
      'Content-Type': 'application/json'
    };
  }
  
  setHeader(key, value) {
    this.headers[key] = value;
  }
  
  async makeRequest(method, url, data = null) {
    const fullUrl = `${this.baseUrl}${url}`;
    const options = {
      method,
      headers: { ...this.headers }
    };
    
    if (data) {
      options.body = JSON.stringify(data);
    }
    
    console.log(`REST: ${method} ${fullUrl}`, data ? `with data: ${JSON.stringify(data)}` : '');
    
    // 模拟 API 响应
    return new Promise(resolve => {
      setTimeout(() => {
        const response = {
          status: 200,
          data: { message: `REST ${method} 请求成功`, url, data }
        };
        resolve(response);
      }, 100);
    });
  }
  
  async get(url, params = {}) {
    const queryString = new URLSearchParams(params).toString();
    const fullUrl = queryString ? `${url}?${queryString}` : url;
    return this.makeRequest('GET', fullUrl);
  }
  
  async post(url, data = {}) {
    return this.makeRequest('POST', url, data);
  }
  
  async put(url, data = {}) {
    return this.makeRequest('PUT', url, data);
  }
  
  async delete(url) {
    return this.makeRequest('DELETE', url);
  }
}

// GraphQL 客户端(被适配者)
class GraphQLClient {
  constructor(endpoint) {
    this.endpoint = endpoint;
    this.headers = {
      'Content-Type': 'application/json'
    };
  }
  
  setHeader(key, value) {
    this.headers[key] = value;
  }
  
  async query(query, variables = {}) {
    console.log(`GraphQL: Query ${query}`, variables ? `with variables: ${JSON.stringify(variables)}` : '');
    
    // 模拟 GraphQL 响应
    return new Promise(resolve => {
      setTimeout(() => {
        const response = {
          data: { message: 'GraphQL 查询成功', query, variables }
        };
        resolve(response);
      }, 100);
    });
  }
  
  async mutate(mutation, variables = {}) {
    console.log(`GraphQL: Mutation ${mutation}`, variables ? `with variables: ${JSON.stringify(variables)}` : '');
    
    // 模拟 GraphQL 响应
    return new Promise(resolve => {
      setTimeout(() => {
        const response = {
          data: { message: 'GraphQL 变更成功', mutation, variables }
        };
        resolve(response);
      }, 100);
    });
  }
}

// gRPC 客户端(被适配者)
class GRPCClient {
  constructor(serviceUrl) {
    this.serviceUrl = serviceUrl;
    this.metadata = new Map();
  }
  
  setMetadata(key, value) {
    this.metadata.set(key, value);
  }
  
  async unaryCall(method, request) {
    console.log(`gRPC: 调用方法 ${method}`, request ? `with request: ${JSON.stringify(request)}` : '');
    
    // 模拟 gRPC 响应
    return new Promise(resolve => {
      setTimeout(() => {
        const response = {
          message: `gRPC 调用 ${method} 成功`,
          method,
          request
        };
        resolve(response);
      }, 100);
    });
  }
  
  async serverStreamingCall(method, request) {
    console.log(`gRPC: 服务器流式调用方法 ${method}`, request ? `with request: ${JSON.stringify(request)}` : '');
    
    // 模拟 gRPC 流式响应
    return new Promise(resolve => {
      setTimeout(() => {
        const response = {
          messages: [
            { message: `gRPC 流式响应 1`, method, request },
            { message: `gRPC 流式响应 2`, method, request },
            { message: `gRPC 流式响应 3`, method, request }
          ]
        };
        resolve(response);
      }, 100);
    });
  }
}

// REST API 适配器
class RESTAdapter extends APIClient {
  constructor(baseUrl) {
    super();
    this.client = new RESTClient(baseUrl);
  }
  
  async get(endpoint, params = {}) {
    return this.client.get(endpoint, params);
  }
  
  async post(endpoint, data = {}) {
    return this.client.post(endpoint, data);
  }
  
  async put(endpoint, data = {}) {
    return this.client.put(endpoint, data);
  }
  
  async delete(endpoint) {
    return this.client.delete(endpoint);
  }
  
  setAuthToken(token) {
    this.client.setHeader('Authorization', `Bearer ${token}`);
  }
}

// GraphQL 适配器
class GraphQLAdapter extends APIClient {
  constructor(endpoint) {
    super();
    this.client = new GraphQLClient(endpoint);
  }
  
  async get(endpoint, params = {}) {
    const query = `query { ${endpoint.replace('/', '')} { ${Object.keys(params).join(' ')} } }`;
    return this.client.query(query, params);
  }
  
  async post(endpoint, data = {}) {
    const mutation = `mutation { ${endpoint.replace('/', '')} { ${Object.keys(data).join(' ')} } }`;
    return this.client.mutate(mutation, data);
  }
  
  async put(endpoint, data = {}) {
    return this.post(endpoint, data);
  }
  
  async delete(endpoint) {
    const mutation = `mutation { delete${endpoint.replace('/', '').charAt(0).toUpperCase() + endpoint.replace('/', '').slice(1)} }`;
    return this.client.mutate(mutation);
  }
  
  setAuthToken(token) {
    this.client.setHeader('Authorization', `Bearer ${token}`);
  }
}

// gRPC 适配器
class GRPCAdapter extends APIClient {
  constructor(serviceUrl) {
    super();
    this.client = new GRPCClient(serviceUrl);
  }
  
  async get(endpoint, params = {}) {
    const method = `Get${endpoint.replace('/', '').charAt(0).toUpperCase() + endpoint.replace('/', '').slice(1)}`;
    return this.client.unaryCall(method, params);
  }
  
  async post(endpoint, data = {}) {
    const method = `Create${endpoint.replace('/', '').charAt(0).toUpperCase() + endpoint.replace('/', '').slice(1)}`;
    return this.client.unaryCall(method, data);
  }
  
  async put(endpoint, data = {}) {
    const method = `Update${endpoint.replace('/', '').charAt(0).toUpperCase() + endpoint.replace('/', '').slice(1)}`;
    return this.client.unaryCall(method, data);
  }
  
  async delete(endpoint) {
    const method = `Delete${endpoint.replace('/', '').charAt(0).toUpperCase() + endpoint.replace('/', '').slice(1)}`;
    return this.client.unaryCall(method);
  }
  
  setAuthToken(token) {
    this.client.setMetadata('authorization', `Bearer ${token}`);
  }
}

// API 客户端管理器
class APIClientManager {
  constructor() {
    this.clients = new Map();
  }
  
  registerClient(name, client) {
    this.clients.set(name, client);
  }
  
  getClient(name) {
    const client = this.clients.get(name);
    if (!client) {
      throw new Error(`未找到 API 客户端: ${name}`);
    }
    return client;
  }
  
  async request(clientName, method, endpoint, data = {}) {
    const client = this.getClient(clientName);
    
    try {
      let response;
      switch (method.toLowerCase()) {
        case 'get':
          response = await client.get(endpoint, data);
          break;
        case 'post':
          response = await client.post(endpoint, data);
          break;
        case 'put':
          response = await client.put(endpoint, data);
          break;
        case 'delete':
          response = await client.delete(endpoint);
          break;
        default:
          throw new Error(`不支持的 HTTP 方法: ${method}`);
      }
      
      console.log(`API 调用成功: ${clientName} ${method} ${endpoint}`);
      return response;
    } catch (error) {
      console.error(`API 调用失败: ${clientName} ${method} ${endpoint}`, error.message);
      throw error;
    }
  }
  
  setAuthToken(clientName, token) {
    const client = this.getClient(clientName);
    client.setAuthToken(token);
  }
}

// 使用示例
async function apiClientExample() {
  const apiManager = new APIClientManager();
  
  // 注册不同类型的 API 客户端
  apiManager.registerClient('rest', new RESTAdapter('https://api.rest-example.com'));
  apiManager.registerClient('graphql', new GraphQLAdapter('https://api.graphql-example.com/graphql'));
  apiManager.registerClient('grpc', new GRPCAdapter('https://api.grpc-example.com'));
  
  // 设置认证令牌
  apiManager.setAuthToken('rest', 'rest_token_123');
  apiManager.setAuthToken('graphql', 'graphql_token_456');
  apiManager.setAuthToken('grpc', 'grpc_token_789');
  
  console.log('=== REST API 调用 ===');
  try {
    const restUsers = await apiManager.request('rest', 'get', '/users', { page: 1, limit: 10 });
    console.log('REST 响应:', restUsers);
    
    const restCreateUser = await apiManager.request('rest', 'post', '/users', { name: '新用户', email: 'newuser@example.com' });
    console.log('REST 创建用户响应:', restCreateUser);
  } catch (error) {
    console.error('REST API 调用失败:', error.message);
  }
  
  console.log('');
  
  console.log('=== GraphQL API 调用 ===');
  try {
    const graphqlUsers = await apiManager.request('graphql', 'get', '/users', { id: 1, name: true, email: true });
    console.log('GraphQL 响应:', graphqlUsers);
    
    const graphqlCreateUser = await apiManager.request('graphql', 'post', '/users', { name: '新用户', email: 'newuser@example.com' });
    console.log('GraphQL 创建用户响应:', graphqlCreateUser);
  } catch (error) {
    console.error('GraphQL API 调用失败:', error.message);
  }
  
  console.log('');
  
  console.log('=== gRPC API 调用 ===');
  try {
    const grpcUsers = await apiManager.request('grpc', 'get', '/users', { id: 1 });
    console.log('gRPC 响应:', grpcUsers);
    
    const grpcCreateUser = await apiManager.request('grpc', 'post', '/users', { name: '新用户', email: 'newuser@example.com' });
    console.log('gRPC 创建用户响应:', grpcCreateUser);
  } catch (error) {
    console.error('gRPC API 调用失败:', error.message);
  }
}

// 运行示例
apiClientExample();

适配器模式的两种实现方式

类适配器

类适配器通过继承来实现适配:

javascript
// 类适配器示例
class ClassAdapter extends Target {
  constructor(adaptee) {
    super();
    this.adaptee = adaptee;
  }
  
  request() {
    // 调用被适配者的方法并转换结果
    return this.adaptee.specificRequest().toUpperCase();
  }
}

对象适配器

对象适配器通过组合来实现适配:

javascript
// 对象适配器示例
class ObjectAdapter {
  constructor(adaptee) {
    this.adaptee = adaptee;
  }
  
  request() {
    // 调用被适配者的方法并转换结果
    return this.adaptee.specificRequest().toLowerCase();
  }
}

适配器模式与其它模式的对比

适配器模式 vs 装饰器模式

javascript
// 适配器模式 - 改变接口
class Adapter {
  constructor(adaptee) {
    this.adaptee = adaptee;
  }
  
  newMethod() {
    return this.adaptee.oldMethod();
  }
}

// 装饰器模式 - 增强功能
class Decorator {
  constructor(component) {
    this.component = component;
  }
  
  operation() {
    // 增强原有功能
    return `装饰后: ${this.component.operation()}`;
  }
}

适配器模式 vs 外观模式

javascript
// 适配器模式 - 转换单个接口
class Adapter {
  request() {
    return this.adaptee.specificRequest();
  }
}

// 外观模式 - 简化复杂子系统
class Facade {
  operation() {
    this.subsystem1.operation1();
    this.subsystem2.operation2();
    this.subsystem3.operation3();
  }
}

适配器模式的优缺点

优点

  1. 单一职责原则:可以将接口或数据转换代码从主要业务逻辑中分离
  2. 开闭原则:只要客户端代码通过目标接口与适配器进行交互,就能在不修改现有客户端代码的情况下添加新类型的适配器
  3. 复用现有代码:可以复用现有的类,即使它们的接口与所需接口不兼容
  4. 灵活性:可以在运行时切换适配器,实现不同的行为

缺点

  1. 复杂性增加:代码整体复杂度增加,因为需要新增一些接口和类
  2. 适配器泛滥:过度使用适配器会让系统变得凌乱,难以维护
  3. 性能开销:适配器在转换过程中可能会带来一些性能开销

总结

适配器模式是一种结构型设计模式,它允许不兼容的接口协同工作。适配器模式通过创建一个适配器类来解决接口不兼容的问题,使得原本由于接口不兼容而不能一起工作的类可以一起工作。

通过本章的学习,我们了解了:

  1. 适配器模式的基本概念和核心思想
  2. 适配器模式的实现方式(类适配器和对象适配器)
  3. 适配器模式在实际开发中的应用场景(支付网关、数据库驱动、API客户端)
  4. 适配器模式与其他结构型模式的对比
  5. 适配器模式的优缺点

适配器模式在现代软件开发中应用广泛,特别是在需要集成第三方库、重构遗留系统或统一多种实现接口的场景中,它可以很好地解决接口不兼容的问题。

在下一章中,我们将继续探讨其他结构型模式,首先是装饰器模式。