设计模式系列(09):结构型模式 - 适配器模式

发布于:2025-06-27 ⋅ 阅读:(12) ⋅ 点赞:(0)

系列导读:完成创建型模式后,我们进入结构型模式的学习。适配器模式是结构型模式的开篇,解决接口不兼容的问题。

解决什么问题:将一个类的接口转换成客户希望的另一个接口,使原本不兼容的类可以一起工作。用于系统集成和第三方库对接。

在软件开发中,我们经常需要使用第三方库或者对接外部系统,但它们的接口往往与我们的系统不兼容。比如,老系统使用XML格式数据,新系统使用JSON格式;或者需要集成的支付接口与现有的支付抽象不匹配。

适配器模式就像现实中的转换插头一样,让不匹配的接口能够正常工作。它在不修改原有代码的前提下,通过一个适配器类来桥接两个不兼容的接口。

本文在系列中的位置


目录

1. 模式概述

适配器模式是一种结构型设计模式,它允许将不兼容的接口转换为客户端期望的接口。适配器模式通过创建一个中间层来解决接口不兼容的问题,使得原本由于接口不兼容而不能一起工作的类可以一起工作。

1.1 定义

适配器模式将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。通过引入适配器,系统可以复用已有的功能模块,提升系统的灵活性和可扩展性。

1.2 目的

  • 实现接口转换,兼容不同系统或模块
  • 提高类的复用性,减少重复开发
  • 降低系统耦合度,提升维护性

2. 使用场景

适配器模式适用于以下场景:

  1. 接口不兼容

    • 新旧系统集成:如老系统接口与新系统不兼容,需要适配。
    • 第三方库使用:引入外部库时接口不一致。
    • 遗留系统改造:升级或重构时需要兼容旧接口。
  2. 类复用

    • 复用现有类:已有类功能满足需求但接口不同。
    • 避免代码重复:通过适配器复用已有实现。
    • 保持接口一致性:对外暴露统一接口。
  3. 系统解耦

    • 降低耦合度:客户端与具体实现解耦。
    • 提高灵活性:可灵活切换不同实现。
    • 便于维护:适配器作为中间层,便于后续扩展。
  4. 多环境适配

    • 跨平台开发:如移动端与PC端接口差异。
    • 多版本支持:兼容不同版本的接口。
    • 环境迁移:如本地与云端接口差异。

真实业务背景举例:

  • 某大型企业在系统升级时,需将老系统的SOAP接口适配为新系统的RESTful接口,避免大规模重构。
  • 金融行业接入多家第三方支付平台,通过适配器统一支付接口,简化业务开发。

3. 优缺点分析

3.1 优点

  1. 接口转换:解决接口不兼容问题,提升系统复用性。保持对外接口一致,便于系统集成。客户端无需修改即可适配新实现。
  2. 灵活性:支持动态适配,便于扩展和维护。可通过组合或继承灵活实现适配。适配器可复用,减少重复开发。
  3. 解耦:降低系统各模块间的耦合度。提高系统内聚性,便于单元测试。便于后续替换和升级实现。

3.2 缺点

  1. 复杂性提升:增加类数量,系统结构更复杂。适配器过多时难以维护。可能引入额外的理解和调试成本。
  2. 性能开销:适配过程可能带来性能损耗。适配器层级过多影响响应速度。内存占用略有增加。
  3. 适用范围有限:只适用于接口不兼容的场景。不能解决所有系统集成问题。适配器本身功能有限,不能滥用。

4. 实际应用案例

  1. 系统集成:新旧系统对接(如ERP系统升级,需兼容老接口)、第三方服务接入(如支付、短信、地图等外部API)、数据格式转换(如XML与JSON互转)。
  2. UI框架:组件适配(如不同UI库的按钮、输入框适配)、样式转换(如主题切换、皮肤适配)、事件处理(如不同事件模型的统一)。
  3. 数据库访问:驱动适配(如JDBC与NoSQL数据库的适配)、方言转换(如SQL语句在不同数据库间的适配)、连接池适配(如不同连接池实现的统一接口)。
  4. 网络通信:协议转换(如HTTP与WebSocket、MQTT等协议适配)、数据格式适配(如Protobuf与JSON、XML互转)、安全适配(如加密、认证方式的适配)。

5. 结构与UML类图

@startuml
package "Adapter Pattern" #DDDDDD {
  interface Target {
    + request(): void
  }
  class Adaptee {
    + specificRequest(): void
  }
  class ClassAdapter extends Adaptee implements Target
  class ObjectAdapter implements Target {
    - adaptee: Adaptee
    + request(): void
  }
  Target <|.. ClassAdapter
  Target <|.. ObjectAdapter
  ObjectAdapter o-- Adaptee : adaptee
  note right: 支持类适配器和对象适配器两种实现
}
@enduml

6. 代码示例

6.1 基本结构示例

业务背景: 实现新旧系统接口适配,通过适配器模式解决接口不兼容问题。

package com.example.patterns.adapter;

import java.util.Objects;

// 目标接口,客户端期望的接口
public interface Target {
    /**
     * 客户端期望的方法
     * 业务含义:新系统统一调用入口
     */
    void request();
}

// 适配者类,已有的老系统类,接口不兼容
public class Adaptee {
    /**
     * 老系统的特殊方法
     * 业务含义:老系统原有功能,无法直接被新系统调用
     */
    public void specificRequest() {
        System.out.println("Adaptee specific request - 老系统业务逻辑执行");
    }
    
    /**
     * 老系统的其他方法,展示复杂性
     */
    public String getData() {
        return "老系统数据";
    }
}

// 类适配器:通过继承实现适配(仅适用于单继承语言)
public class ClassAdapter extends Adaptee implements Target {
    @Override
    public void request() {
        // 适配,将Target接口的调用转为Adaptee的specificRequest
        // 业务说明:新系统调用request时,实际执行老系统逻辑
        try {
            specificRequest();
            // 可以在适配过程中增加额外逻辑
            System.out.println("Class Adapter: 数据=" + getData());
        } catch (Exception e) {
            System.err.println("Class Adapter failed: " + e.getMessage());
            throw new RuntimeException("适配器执行失败", e);
        }
    }
}

// 对象适配器:通过组合实现适配,推荐方式
public class ObjectAdapter implements Target {
    private final Adaptee adaptee;
    
    /**
     * 构造方法注入老系统对象,便于解耦和扩展
     */
    public ObjectAdapter(Adaptee adaptee) {
        this.adaptee = Objects.requireNonNull(adaptee, "Adaptee cannot be null");
    }
    
    @Override
    public void request() {
        try {
            // 适配,将Target接口的调用转为Adaptee的specificRequest
            adaptee.specificRequest();
            // 可以组合多个adaptee的方法
            String data = adaptee.getData();
            System.out.println("Object Adapter: 处理数据=" + data);
        } catch (Exception e) {
            System.err.println("Object Adapter failed: " + e.getMessage());
            throw new RuntimeException("对象适配器执行失败", e);
        }
    }
}

6.2 企业级应用场景:支付系统适配

业务背景: 电商平台需要集成多家第三方支付平台(支付宝、微信、银联),但各平台接口不统一,通过适配器统一支付接口。

package com.example.patterns.adapter.payment;

import java.math.BigDecimal;
import java.util.Map;
import java.util.HashMap;

// 统一支付接口
public interface PaymentProcessor {
    /**
     * 统一支付方法
     * @param amount 支付金额
     * @param orderId 订单ID
     * @return 支付结果
     */
    PaymentResult processPayment(BigDecimal amount, String orderId);
}

// 支付结果封装
public class PaymentResult {
    private boolean success;
    private String transactionId;
    private String message;
    private String paymentChannel;
    
    public PaymentResult(boolean success, String transactionId, String message, String paymentChannel) {
        this.success = success;
        this.transactionId = transactionId;
        this.message = message;
        this.paymentChannel = paymentChannel;
    }
    
    // Getter方法
    public boolean isSuccess() { return success; }
    public String getTransactionId() { return transactionId; }
    public String getMessage() { return message; }
    public String getPaymentChannel() { return paymentChannel; }
    
    @Override
    public String toString() {
        return String.format("PaymentResult{success=%s, transactionId='%s', message='%s', channel='%s'}", 
                success, transactionId, message, paymentChannel);
    }
}

// 支付宝SDK(第三方库,接口不可修改)
public class AlipaySDK {
    public Map<String, Object> alipayTrade(double money, String orderNo) {
        Map<String, Object> result = new HashMap<>();
        if (money > 0 && orderNo != null) {
            result.put("status", "SUCCESS");
            result.put("trade_no", "alipay_" + System.currentTimeMillis());
            result.put("msg", "支付宝支付成功");
        } else {
            result.put("status", "FAILED");
            result.put("msg", "支付宝支付失败");
        }
        return result;
    }
}

// 微信支付SDK(第三方库,接口不可修改)
public class WechatPaySDK {
    public boolean wxPay(int amount, String outTradeNo) {
        // 微信支付以分为单位
        return amount > 0 && outTradeNo != null && !outTradeNo.trim().isEmpty();
    }
    
    public String getTransactionId() {
        return "wx_" + System.currentTimeMillis();
    }
}

// 银联支付SDK(第三方库,接口不可修改)
public class UnionPaySDK {
    public String unionpayProcess(String amt, String orderId) {
        if (amt != null && Double.parseDouble(amt) > 0 && orderId != null) {
            return "00|union_" + System.currentTimeMillis() + "|银联支付成功";
        }
        return "01||银联支付失败";
    }
}

// 支付宝适配器
public class AlipayAdapter implements PaymentProcessor {
    private final AlipaySDK alipaySDK;
    
    public AlipayAdapter() {
        this.alipaySDK = new AlipaySDK();
    }
    
    @Override
    public PaymentResult processPayment(BigDecimal amount, String orderId) {
        try {
            Map<String, Object> result = alipaySDK.alipayTrade(amount.doubleValue(), orderId);
            
            boolean success = "SUCCESS".equals(result.get("status"));
            String transactionId = success ? (String) result.get("trade_no") : null;
            String message = (String) result.get("msg");
            
            return new PaymentResult(success, transactionId, message, "支付宝");
        } catch (Exception e) {
            return new PaymentResult(false, null, "支付宝适配器异常: " + e.getMessage(), "支付宝");
        }
    }
}

// 微信支付适配器
public class WechatPayAdapter implements PaymentProcessor {
    private final WechatPaySDK wechatPaySDK;
    
    public WechatPayAdapter() {
        this.wechatPaySDK = new WechatPaySDK();
    }
    
    @Override
    public PaymentResult processPayment(BigDecimal amount, String orderId) {
        try {
            // 将元转换为分
            int amountInCents = amount.multiply(new BigDecimal("100")).intValue();
            boolean success = wechatPaySDK.wxPay(amountInCents, orderId);
            
            String transactionId = success ? wechatPaySDK.getTransactionId() : null;
            String message = success ? "微信支付成功" : "微信支付失败";
            
            return new PaymentResult(success, transactionId, message, "微信支付");
        } catch (Exception e) {
            return new PaymentResult(false, null, "微信支付适配器异常: " + e.getMessage(), "微信支付");
        }
    }
}

// 银联支付适配器
public class UnionPayAdapter implements PaymentProcessor {
    private final UnionPaySDK unionPaySDK;
    
    public UnionPayAdapter() {
        this.unionPaySDK = new UnionPaySDK();
    }
    
    @Override
    public PaymentResult processPayment(BigDecimal amount, String orderId) {
        try {
            String result = unionPaySDK.unionpayProcess(amount.toString(), orderId);
            String[] parts = result.split("\\|");
            
            boolean success = "00".equals(parts[0]);
            String transactionId = parts.length > 1 ? parts[1] : null;
            String message = parts.length > 2 ? parts[2] : "银联支付处理完成";
            
            return new PaymentResult(success, transactionId, message, "银联支付");
        } catch (Exception e) {
            return new PaymentResult(false, null, "银联支付适配器异常: " + e.getMessage(), "银联支付");
        }
    }
}

// 支付工厂,简化适配器的使用
public class PaymentAdapterFactory {
    public static PaymentProcessor createPaymentProcessor(String paymentType) {
        switch (paymentType.toLowerCase()) {
            case "alipay":
                return new AlipayAdapter();
            case "wechat":
                return new WechatPayAdapter();
            case "unionpay":
                return new UnionPayAdapter();
            default:
                throw new IllegalArgumentException("不支持的支付类型: " + paymentType);
        }
    }
}

6.3 数据格式适配场景

业务背景: 系统需要处理多种数据格式(JSON、XML、CSV),通过适配器统一数据处理接口。

package com.example.patterns.adapter.data;

import java.util.List;
import java.util.Map;
import java.util.ArrayList;
import java.util.HashMap;

// 统一数据处理接口
public interface DataProcessor {
    /**
     * 处理数据
     * @param rawData 原始数据
     * @return 处理后的标准格式数据
     */
    List<Map<String, Object>> processData(String rawData);
}

// JSON处理器(假设已有的库)
public class JsonProcessor {
    public Map<String, Object> parseJson(String json) {
        // 简化的JSON解析逻辑
        Map<String, Object> result = new HashMap<>();
        if (json.contains("\"name\"") && json.contains("\"age\"")) {
            result.put("name", "张三");
            result.put("age", 25);
            result.put("source", "JSON");
        }
        return result;
    }
}

// XML处理器(假设已有的库)
public class XmlProcessor {
    public String[] parseXml(String xml) {
        // 简化的XML解析逻辑
        if (xml.contains("<person>")) {
            return new String[]{"李四", "30", "XML"};
        }
        return new String[]{};
    }
}

// CSV处理器(假设已有的库)
public class CsvProcessor {
    public List<String[]> parseCsv(String csv) {
        List<String[]> result = new ArrayList<>();
        String[] lines = csv.split("\n");
        for (String line : lines) {
            if (!line.trim().isEmpty()) {
                result.add(line.split(","));
            }
        }
        return result;
    }
}

// JSON适配器
public class JsonDataAdapter implements DataProcessor {
    private final JsonProcessor jsonProcessor;
    
    public JsonDataAdapter() {
        this.jsonProcessor = new JsonProcessor();
    }
    
    @Override
    public List<Map<String, Object>> processData(String rawData) {
        List<Map<String, Object>> result = new ArrayList<>();
        try {
            Map<String, Object> parsed = jsonProcessor.parseJson(rawData);
            if (!parsed.isEmpty()) {
                result.add(parsed);
            }
        } catch (Exception e) {
            System.err.println("JSON数据处理失败: " + e.getMessage());
        }
        return result;
    }
}

// XML适配器
public class XmlDataAdapter implements DataProcessor {
    private final XmlProcessor xmlProcessor;
    
    public XmlDataAdapter() {
        this.xmlProcessor = new XmlProcessor();
    }
    
    @Override
    public List<Map<String, Object>> processData(String rawData) {
        List<Map<String, Object>> result = new ArrayList<>();
        try {
            String[] parsed = xmlProcessor.parseXml(rawData);
            if (parsed.length >= 3) {
                Map<String, Object> data = new HashMap<>();
                data.put("name", parsed[0]);
                data.put("age", Integer.parseInt(parsed[1]));
                data.put("source", parsed[2]);
                result.add(data);
            }
        } catch (Exception e) {
            System.err.println("XML数据处理失败: " + e.getMessage());
        }
        return result;
    }
}

// CSV适配器
public class CsvDataAdapter implements DataProcessor {
    private final CsvProcessor csvProcessor;
    
    public CsvDataAdapter() {
        this.csvProcessor = new CsvProcessor();
    }
    
    @Override
    public List<Map<String, Object>> processData(String rawData) {
        List<Map<String, Object>> result = new ArrayList<>();
        try {
            List<String[]> parsed = csvProcessor.parseCsv(rawData);
            for (String[] row : parsed) {
                if (row.length >= 2) {
                    Map<String, Object> data = new HashMap<>();
                    data.put("name", row[0]);
                    data.put("age", Integer.parseInt(row[1]));
                    data.put("source", "CSV");
                    result.add(data);
                }
            }
        } catch (Exception e) {
            System.err.println("CSV数据处理失败: " + e.getMessage());
        }
        return result;
    }
}

// 数据处理管理器
public class DataProcessingManager {
    public static DataProcessor createProcessor(String dataType) {
        switch (dataType.toLowerCase()) {
            case "json":
                return new JsonDataAdapter();
            case "xml":
                return new XmlDataAdapter();
            case "csv":
                return new CsvDataAdapter();
            default:
                throw new IllegalArgumentException("不支持的数据类型: " + dataType);
        }
    }
}

// 客户端使用示例
public class AdapterClient {
    public static void main(String[] args) {
        // 支付系统示例
        PaymentProcessor alipay = PaymentAdapterFactory.createPaymentProcessor("alipay");
        PaymentResult result = alipay.processPayment(new BigDecimal("99.99"), "ORDER_001");
        System.out.println("支付结果: " + result);
        
        // 数据处理示例
        DataProcessor jsonProcessor = DataProcessingManager.createProcessor("json");
        List<Map<String, Object>> data = jsonProcessor.processData("{\"name\":\"张三\",\"age\":25}");
        System.out.println("处理结果: " + data);
    }
    // 总结:通过适配器模式,系统可以灵活集成不同的第三方服务和数据格式,提升了系统的扩展性和维护性。
}

7. 测试用例

业务背景: 验证适配器模式的核心功能,包括基本适配、支付系统适配和数据格式适配。

public class AdapterPatternTest {
    
    @Test
    public void testClassAdapter() {
        // 测试类适配器
        Target target = new ClassAdapter();
        target.request();
        // 验证类适配器能正确调用adaptee的方法
        assertTrue("类适配器应该能正确执行", true);
    }
    
    @Test
    public void testObjectAdapter() {
        // 测试对象适配器
        Adaptee adaptee = new Adaptee();
        Target target = new ObjectAdapter(adaptee);
        target.request();
        // 验证对象适配器能正确调用adaptee的方法
        assertTrue("对象适配器应该能正确执行", true);
    }
    
    @Test
    public void testObjectAdapterWithNullAdaptee() {
        // 测试空对象异常处理
        assertThrows(NullPointerException.class, () -> {
            new ObjectAdapter(null);
        });
    }
    
    @Test
    public void testAlipayAdapter() {
        // 测试支付宝适配器
        PaymentProcessor alipay = new AlipayAdapter();
        PaymentResult result = alipay.processPayment(new BigDecimal("100.00"), "TEST_ORDER_001");
        
        assertNotNull("支付结果不应为空", result);
        assertTrue("支付应该成功", result.isSuccess());
        assertEquals("支付渠道应为支付宝", "支付宝", result.getPaymentChannel());
        assertNotNull("交易ID不应为空", result.getTransactionId());
        assertTrue("交易ID应以alipay开头", result.getTransactionId().startsWith("alipay_"));
    }
    
    @Test
    public void testWechatPayAdapter() {
        // 测试微信支付适配器
        PaymentProcessor wechatPay = new WechatPayAdapter();
        PaymentResult result = wechatPay.processPayment(new BigDecimal("50.00"), "TEST_ORDER_002");
        
        assertNotNull("支付结果不应为空", result);
        assertTrue("支付应该成功", result.isSuccess());
        assertEquals("支付渠道应为微信支付", "微信支付", result.getPaymentChannel());
        assertNotNull("交易ID不应为空", result.getTransactionId());
        assertTrue("交易ID应以wx开头", result.getTransactionId().startsWith("wx_"));
    }
    
    @Test
    public void testUnionPayAdapter() {
        // 测试银联支付适配器
        PaymentProcessor unionPay = new UnionPayAdapter();
        PaymentResult result = unionPay.processPayment(new BigDecimal("200.00"), "TEST_ORDER_003");
        
        assertNotNull("支付结果不应为空", result);
        assertTrue("支付应该成功", result.isSuccess());
        assertEquals("支付渠道应为银联支付", "银联支付", result.getPaymentChannel());
        assertNotNull("交易ID不应为空", result.getTransactionId());
        assertTrue("交易ID应以union开头", result.getTransactionId().startsWith("union_"));
    }
    
    @Test
    public void testPaymentAdapterFactory() {
        // 测试支付适配器工厂
        PaymentProcessor alipay = new AlipayAdapter();
        PaymentProcessor wechat = new WechatPayAdapter();
        PaymentProcessor unionpay = new UnionPayAdapter();
        
        assertTrue("应该创建支付宝适配器", alipay instanceof AlipayAdapter);
        assertTrue("应该创建微信支付适配器", wechat instanceof WechatPayAdapter);
        assertTrue("应该创建银联支付适配器", unionpay instanceof UnionPayAdapter);
        
        // 测试不支持的支付类型
        assertThrows(IllegalArgumentException.class, () -> {
            PaymentAdapterFactory.createPaymentProcessor("unknown");
        });
    }
    
    @Test
    public void testJsonDataAdapter() {
        // 测试JSON数据适配器
        DataProcessor jsonProcessor = new JsonDataAdapter();
        List<Map<String, Object>> result = jsonProcessor.processData("{\"name\":\"张三\",\"age\":25}");
        
        assertNotNull("处理结果不应为空", result);
        assertEquals("应该有一条数据", 1, result.size());
        
        Map<String, Object> data = result.get(0);
        assertEquals("姓名应为张三", "张三", data.get("name"));
        assertEquals("年龄应为25", 25, data.get("age"));
        assertEquals("来源应为JSON", "JSON", data.get("source"));
    }
    
    @Test
    public void testXmlDataAdapter() {
        // 测试XML数据适配器
        DataProcessor xmlProcessor = new XmlDataAdapter();
        List<Map<String, Object>> result = xmlProcessor.processData("<person><name>李四</name><age>30</age></person>");
        
        assertNotNull("处理结果不应为空", result);
        assertEquals("应该有一条数据", 1, result.size());
        
        Map<String, Object> data = result.get(0);
        assertEquals("姓名应为李四", "李四", data.get("name"));
        assertEquals("年龄应为30", 30, data.get("age"));
        assertEquals("来源应为XML", "XML", data.get("source"));
    }
    
    @Test
    public void testCsvDataAdapter() {
        // 测试CSV数据适配器
        DataProcessor csvProcessor = new CsvDataAdapter();
        List<Map<String, Object>> result = csvProcessor.processData("王五,28\n赵六,32");
        
        assertNotNull("处理结果不应为空", result);
        assertEquals("应该有两条数据", 2, result.size());
        
        Map<String, Object> data1 = result.get(0);
        assertEquals("第一条姓名应为王五", "王五", data1.get("name"));
        assertEquals("第一条年龄应为28", 28, data1.get("age"));
        
        Map<String, Object> data2 = result.get(1);
        assertEquals("第二条姓名应为赵六", "赵六", data2.get("name"));
        assertEquals("第二条年龄应为32", 32, data2.get("age"));
    }
    
    @Test
    public void testDataProcessingManager() {
        // 测试数据处理管理器
        DataProcessor jsonProcessor = DataProcessingManager.createProcessor("json");
        DataProcessor xmlProcessor = DataProcessingManager.createProcessor("xml");
        DataProcessor csvProcessor = DataProcessingManager.createProcessor("csv");
        
        assertTrue("应该创建JSON适配器", jsonProcessor instanceof JsonDataAdapter);
        assertTrue("应该创建XML适配器", xmlProcessor instanceof XmlDataAdapter);
        assertTrue("应该创建CSV适配器", csvProcessor instanceof CsvDataAdapter);
        
        // 测试不支持的数据类型
        assertThrows(IllegalArgumentException.class, () -> {
            DataProcessingManager.createProcessor("unknown");
        });
    }
    
    @Test
    public void testPaymentWithInvalidAmount() {
        // 测试无效金额的支付
        PaymentProcessor alipay = new AlipayAdapter();
        PaymentResult result = alipay.processPayment(BigDecimal.ZERO, "INVALID_ORDER");
        
        assertNotNull("支付结果不应为空", result);
        assertFalse("支付应该失败", result.isSuccess());
        assertEquals("支付渠道应为支付宝", "支付宝", result.getPaymentChannel());
    }
    
    @Test
    public void testDataAdapterWithInvalidData() {
        // 测试无效数据的处理
        DataProcessor jsonProcessor = new JsonDataAdapter();
        List<Map<String, Object>> result = jsonProcessor.processData("invalid json");
        
        assertNotNull("处理结果不应为空", result);
        assertTrue("应该返回空列表", result.isEmpty());
    }
}

8. 常见误区与反例

8.1 常见误区

  • 误区1 :滥用适配器模式

    // 错误示例:为了统一接口而过度使用适配器
    public class SimpleStringAdapter implements StringProcessor {
        private String value;
        public SimpleStringAdapter(String value) { this.value = value; }
        public String process() { return value.toLowerCase(); } // 简单操作不需要适配器
    }
    

    正确做法:只在接口真正不兼容时使用适配器,简单操作直接实现即可。

  • 误区2 :适配器包含过多业务逻辑

    // 错误示例:适配器中包含复杂业务逻辑
    public class BadPaymentAdapter implements PaymentProcessor {
        public PaymentResult processPayment(BigDecimal amount, String orderId) {
            // 错误:在适配器中进行业务校验和处理
            if (isVipUser(orderId)) {
                amount = amount.multiply(new BigDecimal("0.9")); // 打折逻辑
            }
            validateOrder(orderId); // 订单校验逻辑
            return thirdPartyPay(amount, orderId);
        }
    }
    

    正确做法:适配器只做接口转换,业务逻辑应在服务层处理。

  • 误区3 :忽略异常处理和参数校验

    // 错误示例:缺少异常处理
    public class UnsafeAdapter implements Target {
        private Adaptee adaptee;
        public void request() {
            adaptee.specificRequest(); // 可能出现NullPointerException
        }
    }
    

8.2 反例分析

  • 反例1 :适配器层级过深
    多个适配器嵌套使用,导致调用链路复杂,性能下降,难以调试。

  • 反例2 :适配器职责不清
    一个适配器试图适配多种不相关的接口,违反单一职责原则。

  • 反例3 :硬编码适配逻辑
    在适配器中硬编码转换规则,缺乏灵活性,难以扩展。

9. 最佳实践

9.1 设计原则

  1. 优先使用对象适配器 :组合优于继承,提供更好的灵活性

    // 推荐:对象适配器
    public class FlexibleAdapter implements Target {
        private final Adaptee adaptee;
        private final ConversionStrategy strategy;
        
        public FlexibleAdapter(Adaptee adaptee, ConversionStrategy strategy) {
            this.adaptee = adaptee;
            this.strategy = strategy;
        }
        
        public void request() {
            strategy.convert(adaptee);
        }
    }
    
  2. 接口设计要单一 :目标接口应简洁明确,避免接口膨胀

    // 推荐:单一职责的接口
    public interface PaymentProcessor {
        PaymentResult processPayment(BigDecimal amount, String orderId);
    }
    
    // 避免:职责过多的接口
    public interface BadPaymentProcessor {
        PaymentResult processPayment(BigDecimal amount, String orderId);
        void sendNotification(String message);
        void generateReport(String orderId);
        void updateInventory(String productId);
    }
    

9.2 实现技巧

  1. 适配器命名规范 :统一命名模式,便于识别和维护

    // 推荐的命名模式
    public class AlipayAdapter implements PaymentProcessor { } // 第三方服务适配器
    public class JsonDataAdapter implements DataProcessor { } // 数据格式适配器
    public class LegacySystemAdapter implements ModernInterface { } // 遗留系统适配器
    
  2. 参数校验和异常处理 :确保适配器健壮性

    // 推荐:完善的异常处理
    public class RobustAdapter implements Target {
        private final Adaptee adaptee;
        
        public RobustAdapter(Adaptee adaptee) {
            this.adaptee = Objects.requireNonNull(adaptee, "Adaptee cannot be null");
        }
        
        public void request() {
            try {
                adaptee.specificRequest();
            } catch (Exception e) {
                log.error("Adapter execution failed", e);
                throw new AdapterException("适配器执行失败", e);
            }
        }
    }
    
  3. 使用工厂模式简化创建 :提供统一的适配器创建接口

    // 推荐:工厂模式创建适配器
    public class AdapterFactory {
        public static PaymentProcessor createPaymentAdapter(PaymentType type) {
            switch (type) {
                case ALIPAY: return new AlipayAdapter();
                case WECHAT: return new WechatPayAdapter();
                case UNIONPAY: return new UnionPayAdapter();
                default: throw new IllegalArgumentException("Unsupported type: " + type);
            }
        }
    }
    

9.3 性能优化

  1. 缓存和资源复用 :避免重复创建昂贵对象

    // 推荐:缓存适配器实例
    public class CachedAdapterFactory {
        private static final Map<String, PaymentProcessor> CACHE = new ConcurrentHashMap<>();
        
        public static PaymentProcessor getPaymentAdapter(String type) {
            return CACHE.computeIfAbsent(type, key -> createAdapter(key));
        }
    }
    
  2. 懒加载和延迟初始化 :按需创建适配器

    // 推荐:懒加载适配器
    public class LazyAdapter implements Target {
        private volatile Adaptee adaptee;
        private final Supplier<Adaptee> adapteeSupplier;
        
        public LazyAdapter(Supplier<Adaptee> adapteeSupplier) {
            this.adapteeSupplier = adapteeSupplier;
        }
        
        public void request() {
            if (adaptee == null) {
                synchronized(this) {
                    if (adaptee == null) {
                        adaptee = adapteeSupplier.get();
                    }
                }
            }
            adaptee.specificRequest();
        }
    }
    

9.4 架构考虑

  1. 配置化适配规则 :通过配置管理适配逻辑

    // 推荐:配置化适配
    @Component
    public class ConfigurableAdapter {
        @Value("${adapter.payment.alipay.endpoint}")
        private String alipayEndpoint;
        
        @Value("${adapter.payment.timeout:5000}")
        private int timeout;
    }
    
  2. 监控和日志 :记录适配过程,便于问题排查

    // 推荐:完善的监控日志
    public class MonitoredAdapter implements Target {
        private static final Logger log = LoggerFactory.getLogger(MonitoredAdapter.class);
        private final MeterRegistry meterRegistry;
        
        public void request() {
            Timer.Sample sample = Timer.start(meterRegistry);
            try {
                log.debug("Starting adapter request");
                adaptee.specificRequest();
                log.info("Adapter request completed successfully");
            } catch (Exception e) {
                log.error("Adapter request failed", e);
                meterRegistry.counter("adapter.errors").increment();
                throw e;
            } finally {
                sample.stop(Timer.builder("adapter.request.duration").register(meterRegistry));
            }
        }
    }
    
  3. 版本兼容性管理 :支持多版本接口适配

    // 推荐:版本化适配器
    public interface VersionedAdapter {
        boolean supports(String version);
        PaymentResult processPayment(BigDecimal amount, String orderId, String version);
    }
    

10. 参考资料与延伸阅读

  • 《设计模式:可复用面向对象软件的基础》GoF
  • Effective Java(中文版)
  • https://refactoringguru.cn/design-patterns/adapter
  • https://www.baeldung.com/java-adapter-pattern

本文为设计模式系列第9篇,后续每篇将聚焦一个设计模式或设计原则,深入讲解实现与应用,敬请关注。


网站公告

今日签到

点亮在社区的每一天
去签到