JavaDog程序狗
发布于 2026-11-03 / 1 阅读
0
0

【设计模式】跟着狗哥复习设计模式(六):适配器模式

换了新手机,老耳机却插不上了。耳机没坏,手机也正常,就是接口对不上。

这时候一般不会拆手机改接口,也不会把好好的耳机扔了。买个转接头,接上就能听。

适配器模式干的活,差不多就是这个意思。

加瓦狗在手机店帮顾客连接老耳机

两边都没坏,就是接不上

新手机只接受 Type-C 耳机,代码里期待的方法叫 play()。

老耳机早就写好了,用的是另一个方法:playWithJack()。

Type-C 和 3.5mm 接口无法直接连接

名字不一样,调用方式也不一样。让手机直接调用老耳机,编译都过不了。

要是旧类来自别人提供的库,咱也不能说改就改。那就加一个中间层,把新接口翻译成旧调用。

手机期待的新接口

先写手机认识的接口:

public interface TypeCHeadphone {
    void play();
}

手机只依赖这个接口,不关心后面接的是新耳机还是老耳机转接头。

public class Phone {
    public void listen(TypeCHeadphone headphone) {
        headphone.play();
    }
}

这就是调用方真正想要的样子。

老耳机已经写好了

旧类的方法对不上:

public class OldHeadphone {
    public void playWithJack() {
        System.out.println("老耳机开始播放音乐");
    }
}

适配器模式中的四个角色

这里别急着改 OldHeadphone。旧代码可能还有别的地方在用,改方法名容易牵一串。

中间加一个转接头

HeadphoneAdapter 实现手机需要的接口,同时保存一只旧耳机。

public class HeadphoneAdapter implements TypeCHeadphone {
    private final OldHeadphone oldHeadphone;

    public HeadphoneAdapter(OldHeadphone oldHeadphone) {
        this.oldHeadphone = Objects.requireNonNull(
                oldHeadphone, "oldHeadphone must not be null"
        );
    }

    @Override
    public void play() {
        oldHeadphone.playWithJack();
    }
}

加入适配器前后的连接变化

手机调用 play(),适配器收到后改去调用 playWithJack()。

适配器没有改手机,也没有改老耳机。它只负责把两边接起来。

调用是怎么走的

把老耳机交给适配器,再把适配器交给手机:

OldHeadphone oldHeadphone = new OldHeadphone();
TypeCHeadphone adapter = new HeadphoneAdapter(oldHeadphone);

Phone phone = new Phone();
phone.listen(adapter);

输出:

老耳机开始播放音乐

play 转成 playWithJack 的调用流程

调用顺序很短:

Phone.listen()
  -> adapter.play()
  -> oldHeadphone.playWithJack()

看着像多绕了一步,其实把不兼容的问题集中到一个类里,其他代码就干净了。

Phone 不用认识老耳机

Phone 的参数类型始终是 TypeCHeadphone。

以后换成真正的 Type-C 耳机,手机代码不用动;接旧耳机时,传入适配器就行。

Phone 只依赖目标接口

调用方只面对自己需要的接口,这是这里很实用的一点。

对象适配器也比较直观:适配器内部装着旧对象,需要时把调用转过去。青岛话说,接口别扭点不要紧,接上能用就行。

啥时候适合加适配器

适配器不是改个参数名就算。

通常是两套已经存在的接口确实对不上,又不适合直接修改其中一边,才需要它。

什么时候适合使用适配器模式

常见情况有这些:

  • 接入旧系统或第三方库;
  • 新代码期待的接口和旧代码不一样;
  • 希望旧类继续用,又不想改调用方;
  • 转换规则想集中放在一个地方。

如果两个类本来就能直接配合,没必要硬塞一个适配器。

狗哥收个尾

适配器模式的核心很简单:接口对不上,就在中间做转换。

手机依赖 TypeCHeadphone,老耳机保留 playWithJack(),HeadphoneAdapter 把两个调用接起来。

旧代码不用推倒重写,新代码也不用知道旧接口的细节。这个转接头,算是没白加。

下一篇继续聊 桥接模式。名字也带个“接”,但解决的问题不一样。


评论