适配器模式(Adapter pattern)

适配器模式是一种结构型设计模式,用于将不同接口的类协同工作。它通过创建一个适配器类来包装原有的类,使两者接口兼容。适配器模式分为类适配器和对象适配器两种实现方式,前者通过继承,后者通过对象组合。此模式在系统需要使用现有类,但其接口不符合需求时非常有用,同时保持了系统和现有类库的解耦。在实际应用中,如电源适配器、JDBC接口的使用等都是适配器模式的实例。
摘要由CSDN通过智能技术生成

类型:结构型模式
要点:适配器继承或依赖已有的对象,实现想要的目标接口

介绍

意图: 将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
主要解决: 主要解决在软件系统中,常常要将一些"现存的对象"放到新的环境中,而新环境要求的接口是现对象不能满足的。
何时使用:

  1. 系统需要使用现有的类,而此类的接口不符合系统的需要。
  2. 想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有一致的接口。
  3. 通过接口转换,将一个类插入另一个类系中。(比如老虎和飞禽,现在多了一个飞虎,在不增加实体的需求下,增加一个适配器,在里面包容一个虎对象,实现飞的接口。)

如何解决: 继承或依赖(推荐)。
关键代码: 适配器继承或依赖已有的对象,实现想要的目标接口。
应用实例:

  1. 美国电器 110V,中国 220V,就要有一个适配器将 110V 转化为 220V。
  2. JAVA JDK 1.1 提供了 Enumeration 接口,而在 1.2 中提供了 Iterator 接口,想要使用 1.2 的 JDK,则要将以前系统的 Enumeration 接口转化为 Iterator 接口,这时就需要适配器模式。
  3. 在 LINUX 上运行 WINDOWS 程序。
  4. JAVA 中的 jdbc。

优点:

  1. 可以让任何两个没有关联的类一起运行。
  2. 提高了类的复用。
  3. 增加了类的透明度。
  4. 灵活性好。‘

缺点:

  1. 过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。
  2. 由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。

使用场景: 有动机地修改一个正常运行的系统的接口,这时应该考虑使用适配器模式。
注意事项: 适配器不是在详细设计时添加的,而是解决正在服役的项目的问题。

应用

第一种:类适配器(采用继承实现)

  • 新建一个类,继承已有的(与现有接口不兼容)类,并实现已有接口
  • 在新建类的实现方法中调用继承类中的方法

在这里插入图片描述

代码举例
  • 插座(非国标)
/**
 * 已存在的接口:插座(非国标)
 */
public interface ChaZuo {

    /**
     * 连接电源和家电
     */
    public void connect();
}
  • 电视机插头(国标)
/**
 * 电视机插头(国标)
 * 已存在的、具有特殊功能、但不符合我们既有的标准接口的类
 */
class ChaTou {
    public void open() {
        System.out.println("(国标)插头的电视机开机啦!");
    }
}
  • 适配器
/**
 * 适配器类,适配插头和插座不匹配问题
 */
public class MyAdapter extends ChaTou implements ChaZuo {

    /**
     * 连接电源和家电
     */
    @Override
    public void connect() {
        System.out.println("正在连接(非国标插座)与(国标插头)...");
        super.open();
    }
}

测试:

public static void main(String[] args) {
        ChaZuo chaZuo = new MyAdapter();
        chaZuo.connect();
    }
}}

结果:

正在连接(非国标插座)与(国标插头)...
(国标)插头的电视机开机啦!

第二种:对象适配器(采用对象组合方式实现)

它不是使用多继承或继承再实现的方式,而是使用直接关联,或者称为委托的方式,类图如下:

在这里插入图片描述

  • 适配器
/**
 * 对象适配器
 * 适配器,适配插头和插座不匹配问题
 */
public class MyAdapter implements ChaZuo {
    
    private ChaTou chaTou;
    
    public MyAdapter (MyAdapter myAdapter) {
        this.chaTou = chaTou;
    }

    /**
     * 连接电源和家电
     */
    @Override
    public void connect() {
        this.chaTou.open();
    }
}

总结

优点

  1. 通过适配器,客户端可以调用同一接口,因而对客户端来说是透明的。这样做更简单、更直接、更紧凑。
  2. 复用了现存的类,解决了现存类和复用环境要求不一致的问题。
  3. 将目标类和适配者类解耦,通过引入一个适配器类重用现有的适配者类,而无需修改原有代码。
  4. 一个对象适配器可以把多个不同的适配者类适配到同一个目标,也就是说,同一个适配器可以把适配者类和它的子类都适配到目标接口。

缺点

  1. 对于对象适配器来说,更换适配器的实现过程比较复杂

适用场景

  1. 系统需要使用现有的类,而这些类的接口不符合系统的接口。
  2. 想要建立一个可以重用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。
  3. 两个类所做的事情相同或相似,但是具有不同接口的时候。
  4. 旧的系统开发的类已经实现了一些功能,但是客户端却只能以另外接口的形式访问,但我们不希望手动更改原有类的时候。
  5. 使用第三方组件,组件接口定义和自己定义的不同,不希望修改自己的接口,但是要使用第三方组件接口的功能。

参考&转载

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用适配器模式实现这个功能。具体实现步骤如下: 1. 定义目标接口:定义一个音频播放器接口,其中包含播放音频的方法。 2. 定义适配器类:定义一个适配器类,实现目标接口,并且内部包含一个能够播放mp3格式音频文件的对象。 3. 通过适配器实现播放:创建一个播放器对象,并创建一个适配器对象,并将能够播放mp3格式音频文件的对象传递给适配器对象。然后调用播放器对象的播放方法,播放mp3格式的音频文件。 示例代码如下所示: ```python # 定义目标接口 class AudioPlayer: def play_audio(self, file_name): pass # 定义适配器类 class Mp3PlayerAdapter(AudioPlayer): def __init__(self, mp3_player): self.mp3_player = mp3_player def play_audio(self, file_name): self.mp3_player.play_mp3(file_name) # mp3播放器 class Mp3Player: def play_mp3(self, file_name): print(f"playing mp3 file: {file_name}") # 实现播放 mp3_player = Mp3Player() adapter = Mp3PlayerAdapter(mp3_player) media_player = MediaPlayer() media_player.play_audio("test.mp4") # 播放mp4格式视频文件 adapter.play_audio("test.mp3") # 播放mp3格式音频文件 ``` 在上面的示例中,我们定义了一个目标接口 `AudioPlayer`,其中包含一个播放音频的方法 `play_audio`。然后我们定义了一个适配器类 `Mp3PlayerAdapter`,实现了目标接口,并且内部包含一个能够播放mp3格式音频文件的对象 `Mp3Player`。在实现播放时,我们先调用 `MediaPlayer` 对象的 `play_audio` 方法,播放mp4格式视频文件,然后通过适配器对象调用 `play_audio` 方法,播放mp3格式音频文件。这样就实现了通过适配器模式让播放器能够播放mp3格式音频文件的功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值