适配器模式 java demo

适配器模式

适配器设计模式是一种结构设计模式,它通过将一个类的接口转换为客户端期望的另一个类来允许不兼容的接口协同工作。

它在以下情况下特别有用:
您正在与与当前界面不匹配的旧系统或第三方库集成。
您希望在不修改其源代码的情况下重用现有功能。
您需要弥合新旧代码之间的差距,或者使用不同接口设计构建的系统之间的差距。

当面对不兼容的接口时,开发人员通常会求助于重写大部分代码或嵌入条件,例如 处理特殊情况。例如,a 可以使用 逻辑来处理现代 和遗留。 if (legacyType)PaymentProcessorif-elseStripeServiceBankTransferAPI

但随着更多不兼容的服务或模块的引入,这种方法很快就会变得混乱、紧密耦合,并违反了开放/封闭原则——使系统难以扩展或重构。

适配器模式通过引入一个位于系统和不兼容组件之间的包装类来解决这个问题 。它将来自您界面的呼叫转换为旧系统或第三方系统可以理解的呼叫,而无需更改任何一端。

让我们通过一个真实世界的示例,看看如何应用适配器模式来无缝集成不兼容的组件并创建更灵活和可维护的架构。

问题:结账流程中的接口不兼容
想象一下,您正在构建电子商务应用程序的结账组件 。

您的结账服务旨在与支付接口配合使用来处理付款。

预期接口
以下是您 希望任何支付提供商遵守的合同:CheckoutService

public interface PaymentProcessor {
    void processPayment(double amount, String currency);
    boolean isPaymentSuccessful();
    String getTransactionId();
}

这种抽象使得在不改变任何核心业务逻辑的情况下交换支付提供商变得容易。

您的内部实施
您的团队已经有一个非常适合此界面的内部支付处理器:

public class InHousePaymentProcessor implements PaymentProcessor {
    private String transactionId;
    private boolean isPaymentSuccessful;

    @Override
    public void processPayment(double amount, String currency) {
        System.out.println("InHousePaymentProcessor: Processing payment of " + amount + " " + currency);
        // Process payment logic
        transactionId = "TXN_" + System.currentTimeMillis();
        isPaymentSuccessful = true;
        System.out.println("InHousePaymentProcessor: Payment successful. Txn ID: " + this.transactionId);
    }

    @Override
    public boolean isPaymentSuccessful() {
        return isPaymentSuccessful;
    }

    @Override
    public String getTransactionId() {
        return transactionId;
    }
}

您 使用此界面并与内部支付处理器完美配合:CheckoutService

public class CheckoutService {
    private PaymentProcessor paymentProcessor;

    public CheckoutService(PaymentProcessor paymentProcessor) {
        this.paymentProcessor = paymentProcessor;
    }

    public void checkout(double amount, String currency) {
        System.out.println("CheckoutService: Attempting to process order for $" + amount + " " + currency);
        paymentProcessor.processPayment(amount, currency);
        if (paymentProcessor.isPaymentSuccessful()) {
            System.out.println("CheckoutService: Order successful! Transaction ID: " + paymentProcessor.getTransactionId());
        } else {
            System.out.println("CheckoutService: Order failed. Payment was not successful.");
        }
    }
}

以下是从您的主要电子商务应用程序调用它的方式:

public class ECommerceAppV1 {
    public static void main(String[] args) {
        PaymentProcessor processor = new InHousePaymentProcessor();
        CheckoutService checkout = new CheckoutService(processor);
        checkout.checkout(199.99, "USD");
    }
}

一切都很顺利。您已将结账业务逻辑与底层支付实现分离,从而实现未来的灵活性。到目前为止干得好。

现在,管理层提出了一个新要求:与传统第三方支付提供商集成,广泛使用并经过实战考验......但界面完全不同。

以下是该旧版支付类的样子:

public class LegacyGateway {
    private long transactionReference;
    private boolean isPaymentSuccessful;

    public void executeTransaction(double totalAmount, String currency) {
        System.out.println("LegacyGateway: Executing transaction for " + currency + " " + totalAmount);
        transactionReference = System.nanoTime();
        isPaymentSuccessful = true;
        System.out.println("LegacyGateway: Transaction executed successfully. Txn ID: " + transactionReference);
    }

    public boolean checkStatus(long transactionReference) {
        System.out.println("LegacyGateway: Checking status for ref: " + transactionReference);
        return isPaymentSuccessful;
    }

    public long getReferenceNumber() {
        return transactionReference;
    }
}

您现在有两个不兼容的接口。您现有 的期望是一个 .但 没有实现它,它的方法和签名不匹配:CheckoutServicePaymentProcessorLegacyGateway

processPayment(double)与。executeTransaction(double, String)

isPaymentSuccessful()与。checkStatus(long)

getTransactionId() vs. (而且它们的类型也不同!getReferenceNumber()

挑战是这样的:
你无法更改 ——它在系统范围内使用并与界面相关联 。CheckoutServicePaymentProcessor
您无法修改 — 它来自外部供应商。LegacyGateway
但你必须让它们一起工作。

您需要的是一个转换器——一个位于 和 之间的类 ,将不兼容的接口调整为适用于您的系统的接口。CheckoutServiceLegacyGateway

这正是适配器设计模式的作用。

适配器模式
适配器充当不兼容接口与客户端实际期望之间的桥梁。

它允许您的系统保持灵活性、可扩展性和解耦性,而无需修改现有的客户端代码或第三方库。

两种类型的适配器
实现适配器有两种主要方法,具体取决于语言和用例:

  1. 1. 对象适配器(Java 中的首选)
    使用组合:适配器保存对适配器(它包装的对象)的引用。
    允许跨类层次结构的灵活性和重用。
    这是 Java 中最常见和推荐的方法。
  2. 2. 类适配器(在 Java 中很少见)
    使用继承:适配器从目标接口和适配器继承。
    需要多重继承,Java 不支持类。
    更适合 C++ 等语言。

在我们的例子中,我们将使用 Object Adapter 模式来适应 接口。LegacyGatewayPaymentProcessor

类图

目标接口(例如,):客户端代码期望和使用的接口。PaymentProcessor

Adaptee(例如):具有不兼容接口的现有类,需要调整。LegacyGateway

适配器:实现 Target 接口并在内部使用 Adaptee 的类。它将 Target 接口上的调用转换为 Adaptee 接口上的调用。

客户端(例如,):系统中使用 Target 接口的部分。CheckoutService

现实世界的类比
想象一下,您正在从美国前往欧洲。您的笔记本电脑充电器使用 A 型插头(在美国使用),但欧洲墙壁插座需要 C 型插头。

您无法直接插入充电器 - 接口不匹配。

您无需购买新充电器,而是使用旅行插头适配器。该设备接受您的 A 型插头并将其转换为适合欧洲插座的 C 型形状。

您不会修改墙上插座(它类似于第三方 API)。
您无需修改充电器(这就像您现有的业务逻辑)。
适配器位于中间并转换连接。

对于我们的示例:
充电器→您的应用 (CheckoutService)
墙壁插座→第三方系统(LegacyGateway)
旅行插头适配器 → 适配器等级 (LegacyGatewayAdapter)

您的应用程序需要一个接口 (),但旧系统提供了另一个接口 ()。该适配器允许两者协同工作,而无需改变任何一侧。PaymentProcessorLegacyGateway

实现适配器
为了将旧类集成 到我们的现代电子商务系统中,我们将创建一个 名为 的对象适配器。LegacyGatewayLegacyGatewayAdapter

这个适配器将实现 我们 已经依赖的接口。在内部,它会将方法调用转换为适当的作, 从而有效地弥合不兼容 API 之间的差距。PaymentProcessorCheckoutServiceLegacyGateway

适配器实现

public class LegacyGatewayAdapter implements PaymentProcessor {
    private LegacyGateway legacyGateway;

    public LegacyGatewayAdapter(LegacyGateway legacyGateway) {
        this.legacyGateway = legacyGateway;
    }

    @Override
    public void processPayment(double amount, String currency) {
        System.out.println("LegacyGatewayAdapter: Processing payment of " + amount + " " + currency);
        legacyGateway.executeTransaction(amount, currency);
        System.out.println("LegacyGatewayAdapter: Payment processed successfully. Txn ID: " + legacyGateway.getReferenceNumber());
    }

    @Override
    public boolean isPaymentSuccessful() {
        return legacyGateway.checkStatus(legacyGateway.getReferenceNumber());
    }

    @Override
    public String getTransactionId() {
        return String.valueOf(legacyGateway.getReferenceNumber());
    }
}

客户端代码保持不变
适配器模式的美妙之处在于,您的客户端代码仍然完全不知道旧版集成。

不 在乎它是处理现代付款还是传统付款,它总是与 .CheckoutServicePaymentProcessor

更新后的客户端代码如下所示:

public class ECommerceAppV2 {
    public static void main(String[] args) {
        PaymentProcessor inHouseProcessor = new InHousePaymentProcessor();
        PaymentProcessor legacyProcessor = new LegacyGatewayAdapter(new LegacyGateway());

        CheckoutService checkoutService = new CheckoutService(inHouseProcessor);
        checkoutService.checkout(100, "USD");

        System.out.println("--------------------------------");

        checkoutService = new CheckoutService(legacyProcessor);
        checkoutService.checkout(100, "USD");
    }
}

是什么让这个适配器工作?
组合胜过继承
我们使用对象组合,而不是继承。适配器包装而不是 子类化它。这使适配器保持:LegacyGateway

松散耦合
更易于测试
更灵活地改变

它还遵循有效的 Java 最佳实践来处理第三方或遗留代码。

方法翻译
中的每个方法 都转换为对旧版 API 的等效调用。这通常包括:PaymentProcessor

重命名或重新映射方法名称
重新组织参数
转换返回类型 — 例如,将 事务引用转换为格式化 的 IDlongString

旧逻辑的封装
适配器保护代码库的其余部分免受旧类的怪癖或结构的影响。从外部看,没有人知道或关心遗留系统正在被使用。

这改进了:
封装
代码可读性
可维护性

其他阅读材料:

https://pan.baidu.com/s/1c1oQItiA7nZxz8Rnl3STpw?pwd=yftc
https://pan.quark.cn/s/dec9e4868381

<think> 我们被要求基于给定的引用内容,回答用户关于Java适配器模式示例代码的问题。用户明确要求示例代码demo)。引用中提供了多个适配器模式的示例代码片段,我们需要从中提取并整合,给出清晰的解释和代码示例。 步骤: 1. 理解适配器模式适配器模式用于使不兼容的接口能够一起工作。它涉及目标接口(客户端期望的接口)、适配器(实现目标接口并包装适配者)和适配者(需要被适配的类)。 2. 分析引用中的示例: - 引用[1]:展示了一个电源适配器示例,将AC220V适配成DC5V。代码中,`PowerAdapter`实现了`DC5`接口,并包装了`AC220`对象。 - 引用[2]:展示了支付处理的适配器,`LegacyGatewayAdapter`实现了`PaymentProcessor`接口,并包装了`LegacyGateway`对象。 - 引用[4]:介绍了一种适配器类的使用方式,即通过一个抽象适配器类(中间类)实现接口的所有方法(空实现),然后让具体类继承该适配器类并重写需要的方法。这是一种类适配器(通过继承)的方式。 - 引用[5]:展示了一个媒体播放器的适配器,它根据音频类型创建不同的高级播放器,并调用相应的方法。这是对象适配器(通过组合)的方式。 注意:适配器模式有两种主要形式:类适配器(使用继承)和对象适配器(使用组合)。在Java中,由于单继承的限制,对象适配器更为常用。 3. 我们选择两个典型的示例进行展示:一个对象适配器示例(如引用[1]或[2])和一个类适配器示例(如引用[4])。 示例1:对象适配器模式(电源适配器) - 目标接口:`DC5`(输出5V直流电) - 适配者:`AC220`(提供220V交流电) - 适配器:`PowerAdapter`,实现`DC5`接口,并持有`AC220`实例。 示例2:类适配器模式(接口方法适配) - 目标接口:`Inter`,有多个方法。 - 适配器类:`InterAdapter`,是一个抽象类,实现了`Inter`接口的所有方法(空实现)。 - 具体类:继承`InterAdapter`,只重写需要的方法。 但是,注意引用[4]中的示例并不是标准的适配器模式(通常用于接口转换),而是一种简化接口实现的方式(也称为缺省适配器模式)。我们也可以将其视为适配器模式的一种变体。 为了更符合用户需求,我们主要展示对象适配器模式,因为这是最常见的。 我们整合引用[1]和引用[2]的示例,给出一个完整的对象适配器示例。 示例:支付处理适配器(类似引用[2]) - 目标接口:`PaymentProcessor`(现代支付处理器接口) - 适配者:`LegacyGateway`(遗留的支付网关,接口不兼容) - 适配器:`LegacyGatewayAdapter`,实现`PaymentProcessor`接口,并持有`LegacyGateway`实例。 由于引用[2]的代码不够完整,我们根据其片段补充完整。 完整代码示例: ```java // 目标接口:PaymentProcessor public interface PaymentProcessor { void processPayment(double amount, String currency); boolean isPaymentSuccessful(); String getTransactionId(); } // 适配者:LegacyGateway(遗留支付网关) public class LegacyGateway { private String referenceNumber; public void executeTransaction(double amount, String currency) { // 执行交易 System.out.println("LegacyGateway: Executing transaction of " + amount + " " + currency); // 假设生成一个参考号 this.referenceNumber = "TXN" + System.currentTimeMillis(); } public String getReferenceNumber() { return referenceNumber; } public boolean checkStatus(String referenceNumber) { // 模拟检查状态,假设总是成功 return true; } } // 适配器:LegacyGatewayAdapter public class LegacyGatewayAdapter implements PaymentProcessor { private LegacyGateway legacyGateway; public LegacyGatewayAdapter(LegacyGateway legacyGateway) { this.legacyGateway = legacyGateway; } @Override public void processPayment(double amount, String currency) { System.out.println("LegacyGatewayAdapter: Processing payment of " + amount + " " + currency); legacyGateway.executeTransaction(amount, currency); System.out.println("LegacyGatewayAdapter: Payment processed successfully. TxnID: " + legacyGateway.getReferenceNumber()); } @Override public boolean isPaymentSuccessful() { return legacyGateway.checkStatus(legacyGateway.getReferenceNumber()); } @Override public String getTransactionId() { return legacyGateway.getReferenceNumber(); } } // 客户端测试 public class AdapterPatternDemo { public static void main(String[] args) { LegacyGateway legacyGateway = new LegacyGateway(); PaymentProcessor processor = new LegacyGatewayAdapter(legacyGateway); processor.processPayment(100.0, "USD"); System.out.println("Payment successful? " + processor.isPaymentSuccessful()); System.out.println("Transaction ID: " + processor.getTransactionId()); } } ``` 运行结果: ``` LegacyGatewayAdapter: Processing payment of 100.0 USD LegacyGateway: Executing transaction of 100.0 USD LegacyGatewayAdapter: Payment processed successfully. TxnID: TXN1621500000000 Payment successful? true Transaction ID: TXN1621500000000 ``` 解释: 1. `PaymentProcessor` 是客户端期望的接口,包含现代支付所需的方法。 2. `LegacyGateway` 是已经存在的类,但其接口(方法)与`PaymentProcessor`不兼容。 3. `LegacyGatewayAdapter` 实现了`PaymentProcessor`接口,并在内部调用`LegacyGateway`的方法,从而完成适配。 这样,客户端就可以通过`PaymentProcessor`接口使用`LegacyGateway`的功能,而无需修改原有代码。 另外,我们也可以简要提一下类适配器模式(通过继承),但由于Java单继承的限制,它不如对象适配器灵活。例如引用[4]的方式: ```java // 目标接口 public interface Inter { void method1(); void method2(); void method3(); void method4(); void method5(); } // 适配器类(缺省适配器) public abstract class InterAdapter implements Inter { public void method1() {} public void method2() {} public void method3() {} public void method4() {} public void method5() {} } // 具体实现类,只重写需要的方法 public class ConcreteInter extends InterAdapter { @Override public void method1() { System.out.println("ConcreteInter: method1"); } } ``` 这种方式适用于我们只需要接口中部分方法的情况,避免了实现所有方法的繁琐。 总结:适配器模式使得原本由于接口不兼容而不能一起工作的类可以一起工作。在Java中,对象适配器(组合)更为常见和灵活。 最后,根据要求生成相关问题。 </think>### Java适配器模式示例代码详解 适配器模式用于解决接口不兼容问题,让原本无法协同工作的类可以一起工作。以下是两种常见的实现方式及代码示例: **1. 对象适配器(通过组合实现)** ```java // 目标接口(客户端期望的接口) interface DC5 { void outputDC5V(); } // 被适配者(已有功能,但接口不兼容) class AC220 { public int outputAC220V() { return 220; } } // 适配器(实现目标接口并包装被适配者) class PowerAdapter implements DC5 { private AC220 ac220; public PowerAdapter(AC220 ac220) { this.ac220 = ac220; } @Override public void outputDC5V() { int voltage = ac220.outputAC220V(); System.out.println("转换电压: " + voltage + "V -> 5V"); } } // 客户端调用 public class Client { public static void main(String[] args) { DC5 adapter = new PowerAdapter(new AC220()); adapter.outputDC5V(); // 输出: 转换电压: 220V -> 5V } } ``` **原理**:适配器类 `PowerAdapter` 实现目标接口 `DC5`,内部持有一个 `AC220` 实例,在 `outputDC5V()` 方法中调用被适配者的方法并转换结果[^1]。 **2. 类适配器(通过继承实现)** ```java // 目标接口 interface MediaPlayer { void play(String audioType, String fileName); } // 被适配者接口 interface AdvancedMediaPlayer { void playVlc(String fileName); void playMp4(String fileName); } // 具体被适配者 class VlcPlayer implements AdvancedMediaPlayer { @Override public void playVlc(String fileName) { System.out.println("播放VLC文件: " + fileName); } @Override public void playMp4(String fileName) {} // 空实现 } // 适配器(继承被适配者并实现目标接口) class MediaAdapter extends VlcPlayer implements MediaPlayer { @Override public void play(String audioType, String fileName) { if(audioType.equalsIgnoreCase("vlc")) { super.playVlc(fileName); // 复用父类功能 } } } // 客户端调用 public class Client { public static void main(String[] args) { MediaPlayer player = new MediaAdapter(); player.play("vlc", "movie.vlc"); // 输出: 播放VLC文件: movie.vlc } } ``` **原理**:适配器 `MediaAdapter` 继承 `VlcPlayer` 获得功能,同时实现 `MediaPlayer` 接口满足客户端调用[^5]。 **关键点**: 1. **对象适配器**更灵活(符合合成复用原则),推荐优先使用 2. **类适配器**需通过继承,可能受限于单继承机制 3. 适配器隐藏了接口转换细节,客户端只需调用目标接口[^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值