适配器模式概述
大体介绍
适配器模式(Adapter Pattern)是一种结构型设计模式,其核心目的是通过提供一个适配器类来使得原本接口不兼容的类可以一起工作。它通过将一个类的接口转换成客户端所期望的接口,使得原本因接口不兼容而无法一起工作的类可以协同工作。
适配器模式的定义
适配器模式是一种结构型设计模式,允许将一个类的接口转换成客户希望的另一个接口,从而解决由于接口不兼容而导致的类无法协同工作的难题。
适配器模式的组成部分
- 目标接口(Target):客户端所期望的接口,可以是现有的接口,也可以是新定义的接口。
- 源接口(Adaptee):需要适配的现有接口,它和目标接口不兼容。
- 适配器(Adapter):负责将源接口转化为目标接口的类,它实现目标接口,并且在方法内部调用源接口的实现,从而使得客户端可以使用目标接口与源接口进行交互。
适配器模式的工作流程
- 客户端调用目标接口的相关方法,而目标接口的实现由适配器来提供。
- 适配器将客户端的请求转化成源接口可以理解的请求,完成适配过程。
- 通过适配器,客户端无需改变代码,只需通过适配器与源接口协作即可。
适配器模式的类型
- 类适配器(Class Adapter):通过继承的方式实现目标接口和源接口的适配。适配器类继承了源接口的实现类,并实现目标接口。
- 对象适配器(Object Adapter):通过组合的方式实现目标接口和源接口的适配。适配器类包含源接口的实例,并通过代理调用源接口的方法来适配目标接口。
适配器模式的优缺点
优点:
- 可以增加类的透明性:客户端可以通过目标接口与类交互,而无需了解适配器的存在,适配器隐藏了源接口的复杂性。
- 增强系统的可扩展性:可以通过适配器模式对现有的类进行改造,使其具备新功能,而不需要修改源代码。
- 支持多个不同的接口:适配器可以将多个不同的接口适配到一个目标接口,提升系统的灵活性。
缺点:
- 增加代码复杂性:每个源接口都需要一个适配器类,这可能会导致系统中出现大量的适配器类,增加代码复杂性。
- 可能会影响性能:每次调用方法时都需要通过适配器进行转发,可能会对系统性能产生一定的影响。
适配器模式的应用场景
适配器模式非常适用于以下几种场景:
- 需要使用现有类,但其接口不符合需求时:通过适配器将源类的接口转化为目标接口。
- 希望类可以和不兼容的接口一起工作时:可以通过适配器模式将不兼容的接口适配成兼容接口,避免直接修改类的代码。
- 在复用已有的类库时:有时第三方库的接口可能与现有系统接口不兼容,可以通过适配器模式使其兼容。
- 希望系统中的多个接口能够统一时:可以通过适配器模式将多个接口统一为一个目标接口,简化系统的调用。
适配器模式的例子
- MediaPlayer:目标接口,客户端通过它来播放不同类型的媒体(MP3,MP4,VLC)。
- AudioPlayer:适配者类,负责播放音频,在加入适配器之前只能播放MP3。
- MP4Player 和 VLCPlayer:高级接口,分别支持播放 MP4 格式和 VLC 格式的媒体。
- MediaAdapter:适配器类,负责将不兼容的接口(如
MP4Player
和VLCPlayer
)适配到MediaPlayer
接口。
接下来,我们将逐步详细解析这个例子。
// 目标接口:MediaPlayer
interface MediaPlayer {void play(String audioType, String fileName);
}// 具体类:AudioPlayer
class AudioPlayer implements MediaPlayer {MediaAdapter mediaAdapter;@Overridepublic void play(String audioType, String fileName) {// 播放MP3文件if(audioType.equalsIgnoreCase("mp3")){System.out.println("Playing mp3 file. Name: " + fileName);}// 对于其他文件类型,通过适配器来处理else if(audioType.equalsIgnoreCase("mp4") || audioType.equalsIgnoreCase("vlc")){mediaAdapter = new MediaAdapter(audioType);mediaAdapter.play(audioType, fileName);}else {System.out.println("Invalid media. " + audioType + " format not supported");}}
}// 原接口:AdvancedMediaPlayer
interface AdvancedMediaPlayer {void playVlc(String fileName);void playMp4(String fileName);
}// 具体类:VlcPlayer(实现AdvancedMediaPlayer)
class VlcPlayer implements AdvancedMediaPlayer {@Overridepublic void playVlc(String fileName) {System.out.println("Playing vlc file. Name: " + fileName);}@Overridepublic void playMp4(String fileName) {// 无法播放 MP4 文件}
}// 具体类:Mp4Player(实现AdvancedMediaPlayer)
class Mp4Player implements AdvancedMediaPlayer {@Overridepublic void playVlc(String fileName) {// 无法播放 VLC 文件}@Overridepublic void playMp4(String fileName) {System.out.println("Playing mp4 file. Name: " + fileName);}
}// 适配器类:MediaAdapter
class MediaAdapter implements MediaPlayer {AdvancedMediaPlayer advancedMusicPlayer;public MediaAdapter(String audioType){if(audioType.equalsIgnoreCase("vlc")){advancedMusicPlayer = new VlcPlayer();}else if(audioType.equalsIgnoreCase("mp4")){advancedMusicPlayer = new Mp4Player();}}@Overridepublic void play(String audioType, String fileName) {if(audioType.equalsIgnoreCase("vlc")){advancedMusicPlayer.playVlc(fileName);}else if(audioType.equalsIgnoreCase("mp4")){advancedMusicPlayer.playMp4(fileName);}}
}// 客户端代码:AdapterPatternDemo
public class AdapterPatternDemo {public static void main(String[] args) {AudioPlayer audioPlayer = new AudioPlayer();audioPlayer.play("mp3", "beyond the horizon.mp3");audioPlayer.play("mp4", "alone.mp4");audioPlayer.play("vlc", "far far away.vlc");audioPlayer.play("avi", "mind me.avi");}
}
代码结构分析
-
目标接口:
MediaPlayer
- 这是客户端所期望的接口,用于播放不同类型的媒体。客户端只通过这个接口来播放音频,不需要关心具体播放的是 MP3、MP4 还是 VLC 格式的文件。
interface MediaPlayer {void play(String audioType, String fileName); }
-
具体类:
AudioPlayer
AudioPlayer
是实现了MediaPlayer
接口的类,支持播放 MP3 格式的音频文件。- 对于 MP4 和 VLC 格式的音频,
AudioPlayer
无法直接播放。于是它会通过MediaAdapter
来适配这些格式。
class AudioPlayer implements MediaPlayer {MediaAdapter mediaAdapter;@Overridepublic void play(String audioType, String fileName) {if(audioType.equalsIgnoreCase("mp3")){System.out.println("Playing mp3 file. Name: " + fileName);}else if(audioType.equalsIgnoreCase("mp4") || audioType.equalsIgnoreCase("vlc")){mediaAdapter = new MediaAdapter(audioType);mediaAdapter.play(audioType, fileName);}else {System.out.println("Invalid media. " + audioType + " format not supported");}} }
这里,
AudioPlayer
通过判断音频格式来决定是否使用适配器。它直接播放 MP3 文件,对于 MP4 和 VLC 文件则通过MediaAdapter
进行适配。 -
原接口:
AdvancedMediaPlayer
AdvancedMediaPlayer
是一个原接口,定义了播放 MP4 和 VLC 格式文件的方法。- 它有两个实现类:
VlcPlayer
和Mp4Player
。这些类分别负责播放各自支持的格式,但它们的接口与MediaPlayer
不兼容。
interface AdvancedMediaPlayer {void playVlc(String fileName);void playMp4(String fileName); }
VlcPlayer
负责播放.vlc
文件,Mp4Player
负责播放.mp4
文件。两个类的接口都与MediaPlayer
不兼容,因此我们需要适配器来实现兼容。 -
适配器类:
MediaAdapter
MediaAdapter
是核心的适配器类,它将不兼容的接口(AdvancedMediaPlayer
)转换为客户端需要的接口(MediaPlayer
)。- 它实现了
MediaPlayer
接口,并根据需要调用VlcPlayer
或Mp4Player
的相应方法。
class MediaAdapter implements MediaPlayer {AdvancedMediaPlayer advancedMusicPlayer;public MediaAdapter(String audioType) {if(audioType.equalsIgnoreCase("vlc")){advancedMusicPlayer = new VlcPlayer();} else if(audioType.equalsIgnoreCase("mp4")){advancedMusicPlayer = new Mp4Player();}}@Overridepublic void play(String audioType, String fileName) {advancedMusicPlayer.play(fileName); // 直接调用通用的 play 方法}
}
MediaAdapter
根据传入的音频类型(vlc
或mp4
)创建相应的AdvancedMediaPlayer
对象。- 然后它会调用
VlcPlayer
或Mp4Player
的playVlc()
或playMp4()
方法,完成对 VLC 或 MP4 文件的播放。
-
客户端代码:
AdapterPatternDemo
- 客户端通过
AudioPlayer
来播放各种格式的音频文件。即使客户端只知道MediaPlayer
接口,它依然可以播放 MP3、MP4 和 VLC 文件,因为AudioPlayer
通过MediaAdapter
实现了适配功能。
public class AdapterPatternDemo {public static void main(String[] args) {AudioPlayer audioPlayer = new AudioPlayer();audioPlayer.play("mp3", "beyond the horizon.mp3");audioPlayer.play("mp4", "alone.mp4");audioPlayer.play("vlc", "far far away.vlc");audioPlayer.play("avi", "mind me.avi");} }
- 客户端通过
运行结果
Playing mp3 file. Name: beyond the horizon.mp3
Playing mp4 file. Name: alone.mp4
Playing vlc file. Name: far far away.vlc
Invalid media. avi format not supported
详细解释
-
目标接口
MediaPlayer
:定义了play
方法,所有的播放器类(AudioPlayer
和适配器)都实现了这个接口。 -
AudioPlayer
类:实现了MediaPlayer
接口,直接支持播放 MP3 文件。对于其他格式(mp4
和vlc
),它创建MediaAdapter
来适配这两种格式并播放相应的文件。 -
MediaAdapter
类:适配器的核心作用是将VlcPlayer
和Mp4Player
的方法适配到MediaPlayer
接口。MediaAdapter
使得AudioPlayer
可以播放 MP4 和 VLC 格式的文件,尽管AudioPlayer
为什么适配器类也要实现MediaPlayer接口?
在适配器模式(Adapter Pattern)中,适配器类实现目标接口(在这个例子中是 MediaPlayer
接口)是非常关键的一步。下面我会详细解释为什么适配器类需要实现目标接口,结合本例进一步展开。
适配器模式的基本概念
适配器模式的核心目标是使得两个接口不兼容的类能够一起工作。适配器类充当“桥梁”的角色,它通过实现目标接口,将现有的、与目标接口不兼容的类适配成我们需要的接口形式。
目标接口(MediaPlayer
)
在本例中,MediaPlayer
是客户端期望使用的接口,它提供了一个统一的播放方法 play()
,客户端通过这个接口来播放音频,不关心具体的实现细节。
interface MediaPlayer {void play(String audioType, String fileName);
}
原接口(AdvancedMediaPlayer
)
原接口 AdvancedMediaPlayer
提供了播放 MP4 和 VLC 格式文件的接口。这个接口并不与 MediaPlayer
接口兼容,无法直接被客户端使用。
interface AdvancedMediaPlayer {void playVlc(String fileName);void playMp4(String fileName);
}
适配器类(MediaAdapter
)
适配器类的作用是将不兼容的 AdvancedMediaPlayer
类适配为 MediaPlayer
接口。为了使适配器能够统一提供 MediaPlayer
的 play()
方法,它需要实现 MediaPlayer
接口。
class MediaAdapter implements MediaPlayer {AdvancedMediaPlayer advancedMusicPlayer;public MediaAdapter(String audioType) {if(audioType.equalsIgnoreCase("vlc")){advancedMusicPlayer = new VlcPlayer();} else if(audioType.equalsIgnoreCase("mp4")){advancedMusicPlayer = new Mp4Player();}}@Overridepublic void play(String audioType, String fileName) {advancedMusicPlayer.play(fileName); // 调用适配器的 play 方法}
}
为什么适配器需要实现 MediaPlayer
接口
-
统一接口,符合客户端需求
- 客户端希望通过
MediaPlayer
接口来播放各种格式的音频文件。AudioPlayer
类和MediaAdapter
都需要实现MediaPlayer
接口。 AudioPlayer
类直接实现MediaPlayer
接口,处理 MP3 文件。而对于 MP4 和 VLC 格式的音频文件,AudioPlayer
则委托给MediaAdapter
。- 如果
MediaAdapter
不实现MediaPlayer
接口,客户端就无法通过统一的接口来播放所有音频格式,AudioPlayer
也无法直接调用它。
- 客户端希望通过
-
符合适配器模式的设计原则
- 适配器模式的本质是“将一个接口适配成另一个接口”。适配器类需要实现目标接口(即
MediaPlayer
接口),才能充当桥梁,把不兼容的接口(如AdvancedMediaPlayer
)适配为客户端需要的接口。 - 客户端通过目标接口(
MediaPlayer
)与AudioPlayer
和MediaAdapter
交互,客户端不需要关心背后具体的实现细节(如VlcPlayer
或Mp4Player
)。
- 适配器模式的本质是“将一个接口适配成另一个接口”。适配器类需要实现目标接口(即
-
增强灵活性和可扩展性
- 通过让
MediaAdapter
实现MediaPlayer
接口,系统的设计更加灵活。当需要添加新的音频格式支持时,我们只需要创建一个新的播放器(比如AviPlayer
)并让它实现AdvancedMediaPlayer
接口。然后,只需扩展MediaAdapter
来支持新格式,无需修改客户端的代码。 - 适配器的职责是将一个接口转换为另一个接口。如果
MediaAdapter
没有实现MediaPlayer
接口,那么AudioPlayer
就无法通过MediaAdapter
播放新格式的文件,从而破坏了代码的可扩展性。
- 通过让
-
与客户端的耦合
- 由于
MediaAdapter
实现了MediaPlayer
接口,客户端代码(例如AudioPlayer
)无需关心其背后是如何实现的,只要通过MediaPlayer
接口进行调用即可。客户端依赖于接口而非实现,这符合面向接口编程的设计思想。 - 如果适配器类不实现
MediaPlayer
接口,客户端将无法调用它的play()
方法,客户端就会与AdvancedMediaPlayer
紧密耦合,失去了适配器的意义。
- 由于
总结
适配器类需要实现 MediaPlayer
接口,目的是:
- 统一接口:使得
MediaAdapter
能与AudioPlayer
一样,通过MediaPlayer
接口来播放音频文件,客户端代码不会因为使用了不同类型的播放器而发生变化。 - 遵循适配器模式的原则:适配器模式的核心是将一个接口转换成另一个接口,适配器类通过实现目标接口来实现这一转换。
- 提高灵活性和扩展性:通过实现目标接口,适配器类可以轻松支持新格式,增强系统的可扩展性。
通过这种设计,客户端的代码不会受到播放器具体实现的影响,保持了系统的解耦,也为未来的扩展提供了便利。
若有新的媒体格式播放需求,该如何修改该适配器?
如果有新的媒体格式播放需求(比如新增 .avi
格式支持),你可以按照以下步骤修改适配器模式中的代码来支持新的格式。我们将以 .avi
格式为例,来展示如何修改适配器和相关代码。
1. 修改 AdvancedMediaPlayer
接口
首先,在 AdvancedMediaPlayer
接口中增加一个新的方法 playAvi
,用于播放 .avi
格式的文件。
// 原有的接口
interface AdvancedMediaPlayer {void playVlc(String fileName);void playMp4(String fileName);// 新增支持的 .avi 格式void playAvi(String fileName);
}
2. 新增实现类 AviPlayer
接下来,为 .avi
格式创建一个新的播放器实现类 AviPlayer
,实现 AdvancedMediaPlayer
接口,并实现 playAvi
方法。
class AviPlayer implements AdvancedMediaPlayer {@Overridepublic void playVlc(String fileName) {// 不支持 VLC 格式}@Overridepublic void playMp4(String fileName) {// 不支持 MP4 格式}@Overridepublic void playAvi(String fileName) {System.out.println("Playing AVI file: " + fileName);}
}
3. 修改 MediaAdapter
类
为了支持 .avi
格式,你需要修改 MediaAdapter
类,增加对 .avi
格式的适配处理。我们可以通过在 MediaAdapter
构造函数中判断传入的格式,并创建对应的播放器对象。
class MediaAdapter implements MediaPlayer {AdvancedMediaPlayer advancedMusicPlayer;public MediaAdapter(String audioType) {if (audioType.equalsIgnoreCase("vlc")) {advancedMusicPlayer = new VlcPlayer();} else if (audioType.equalsIgnoreCase("mp4")) {advancedMusicPlayer = new Mp4Player();} else if (audioType.equalsIgnoreCase("avi")) {advancedMusicPlayer = new AviPlayer(); // 新增对 .avi 格式的支持}}@Overridepublic void play(String audioType, String fileName) {if (audioType.equalsIgnoreCase("vlc")) {advancedMusicPlayer.playVlc(fileName);} else if (audioType.equalsIgnoreCase("mp4")) {advancedMusicPlayer.playMp4(fileName);} else if (audioType.equalsIgnoreCase("avi")) {advancedMusicPlayer.playAvi(fileName); // 调用新实现的 playAvi 方法}}
}
4. 修改 AudioPlayerClient
类
最后,在 AudioPlayerClient
中,你需要确保 .avi
格式的播放器被正确使用。当你通过 MediaAdapter
类来适配 .avi
格式时,你可以直接使用它播放 .avi
文件。
class AudioPlayerClient {MediaPlayer audioPlayer;public AudioPlayerClient(MediaPlayer audioPlayer) {this.audioPlayer = audioPlayer;}public void playMedia(String audioType, String fileName) {audioPlayer.play(audioType, fileName);}
}
5. 客户端调用
现在,客户端可以通过 MediaAdapter
来支持播放 .avi
格式的音频文件了。你只需将 .avi
格式的请求传递给 AudioPlayerClient
,MediaAdapter
会根据格式自动选择正确的播放器。
public class Main {public static void main(String[] args) {AudioPlayerClient audioPlayerClient = new AudioPlayerClient(new AudioPlayer());// 测试 MP3 格式audioPlayerClient.playMedia("mp3", "beyond the horizon.mp3");// 测试 VLC 格式audioPlayerClient.playMedia("vlc", "far far away.vlc");// 测试 AVI 格式audioPlayerClient.playMedia("avi", "mind me.avi"); // 新增的 AVI 格式}
}
代码总结
- 修改接口:在
AdvancedMediaPlayer
接口中新增对.avi
格式播放的支持(即增加playAvi
方法)。 - 新增实现类:为
.avi
格式创建一个新的播放器类AviPlayer
,并实现播放逻辑。 - 修改适配器:在
MediaAdapter
中增加对.avi
格式的支持,在play
方法中进行格式判断,并调用AviPlayer
的playAvi
方法。 - 客户端调用:客户端不需要关心具体实现,只需调用
MediaAdapter
来处理不同的音频格式。
优势
- 扩展性强:当你需要支持新的音频格式时,只需添加一个新的实现类并修改适配器类,而不需要修改现有的客户端代码或其他播放器类。
- 符合开闭原则:现有的代码对修改是封闭的,对扩展是开放的。你只需扩展系统,而不需要修改现有的功能。
- 职责分离清晰:每个播放器类只负责一个格式的播放,适配器类负责将客户端请求转发到正确的播放器类,代码结构更加清晰。
这样,如果以后还需要增加新的格式,只需要按照这种方式新增相关的播放器实现和适配逻辑,而不需要对现有代码进行过多修改,确保系统能够灵活扩展。
面向接口的编程与适配器设计模式
面向接口的编程(Interface-based Programming)和适配器模式(Adapter Pattern)都与接口有很大的关系,它们的设计理念和应用场景有所不同。我们可以通过以下几个方面来对比这两者:
1. 基本概念
面向接口的编程:
面向接口的编程是一种设计方法,它强调通过接口来抽象对象的行为,定义不同对象可以遵循的规则或契约。接口只定义行为,不关心具体的实现。
- 目标: 实现灵活、解耦和可扩展的设计,减少模块之间的耦合度。
- 特点: 类之间通过接口进行交互,具体的实现可以替换而不影响其他部分的代码。
适配器模式:
适配器模式是一种结构型设计模式,它的目的是将一个类的接口转换成客户期望的另一个接口。适配器模式通过引入适配器类来“适配”现有的接口,使得原本由于接口不兼容而无法一起工作的类可以一起工作。
- 目标: 通过一个适配器类,处理接口不兼容的问题,让不同的接口能够共同工作。
- 特点: 适配器类在原有接口和目标接口之间进行转换。
2. 结构差异
面向接口的编程:
- 接口定义: 在面向接口的编程中,我们定义多个接口,多个类可以实现不同的接口。
- 接口实现: 类根据需要实现接口中的方法。不同的实现类提供不同的行为,而客户端代码只依赖于接口,而不关心具体的实现。
// 面向接口的编程:定义接口并实现
interface MediaPlayer {void play(String audioType, String fileName);
}class AudioPlayer implements MediaPlayer {@Overridepublic void play(String audioType, String fileName) {if(audioType.equalsIgnoreCase("mp3")){System.out.println("Playing mp3 file. Name: " + fileName);}}
}
适配器模式:
- 目标接口和适配接口: 适配器模式涉及两个接口:目标接口(客户端期望的接口)和 适配接口(被适配的接口)。适配器类将被适配的接口转化为目标接口,确保客户端可以以一致的方式调用。
- 适配器实现: 适配器类实现目标接口,并将客户端请求转换为被适配接口的方法调用。
// 适配器模式:适配器将不同格式的播放器统一适配为目标接口 MediaPlayer
interface MediaPlayer {void play(String audioType, String fileName);
}interface AdvancedMediaPlayer {void playVlc(String fileName);void playMp4(String fileName);
}class VlcPlayer implements AdvancedMediaPlayer {@Overridepublic void playVlc(String fileName) {System.out.println("Playing vlc file. Name: " + fileName);}@Overridepublic void playMp4(String fileName) {// Do nothing}
}class MediaAdapter implements MediaPlayer {AdvancedMediaPlayer advancedMusicPlayer;public MediaAdapter(String audioType) {if(audioType.equalsIgnoreCase("vlc")){advancedMusicPlayer = new VlcPlayer();}}@Overridepublic void play(String audioType, String fileName) {if(audioType.equalsIgnoreCase("vlc")){advancedMusicPlayer.playVlc(fileName);}}
}
3. 核心目的和适用场景
面向接口的编程:
- 目的: 提供高内聚、低耦合的设计。通过接口定义一组行为规范,允许不同的实现类提供具体的实现。接口的抽象为系统的扩展提供了灵活性。
- 适用场景:
- 你需要一个类的多个实现,并且希望能够在运行时根据需要切换实现。
- 你希望实现代码复用和解耦,使得类和类之间的依赖最小化。
- 比如,多个类实现一个通用的
MediaPlayer
接口,处理不同格式的音频播放。
适配器模式:
- 目的: 解决接口不兼容的问题。通过引入适配器类来将不兼容的接口转换为目标接口,使得原本不能协同工作的类能够一起工作。
- 适用场景:
- 你有一个现有的类(比如第三方库提供的类),它有一个不符合你当前系统设计的接口,但你无法更改这个类。
- 你希望将现有的类与新的接口或者类集成,且不想修改现有的类代码。
- 比如,你需要通过适配器将旧的
.mp3
播放器与新接口集成。
4. 代码复用 vs. 代码桥接
面向接口的编程:
- 代码复用: 面向接口的编程通过接口和抽象类为不同的实现提供复用机会。不同类的实现可以根据需求复用相同的接口。
- 举例:
AudioPlayer
类可以复用MediaPlayer
接口并实现多种格式的播放,如.mp3
、.mp4
。
适配器模式:
- 代码桥接: 适配器模式并不要求重写所有的实现类,而是通过创建适配器类,来在两个不同接口间建立桥梁。适配器类实现目标接口并委托给被适配类来执行实际的工作。
- 举例:
MediaAdapter
类作为适配器,桥接了MediaPlayer
接口和AdvancedMediaPlayer
接口之间的差异,将.vlc
播放的请求委托给VlcPlayer
类的playVlc
方法。
5. 灵活性与扩展性
面向接口的编程:
- 灵活性: 高度依赖接口定义,使得代码能够更容易被扩展和替换。客户端与接口解耦,允许替换不同的实现类。
- 扩展性: 新的实现类可以根据需要随时添加,不影响已有代码,只要新的实现类遵循相同的接口。
适配器模式:
- 灵活性: 在不修改现有代码的前提下,能够使现有类与新接口兼容。适配器模式提供了兼容性,即使原始接口和目标接口之间不兼容,也能通过适配器来解决。
- 扩展性: 如果需要支持新的格式,适配器模式允许你添加新的适配器类,而不需要修改现有的代码。
6. 代码实例对比
面向接口编程示例:
interface MediaPlayer {void play(String audioType, String fileName);
}class AudioPlayer implements MediaPlayer {@Overridepublic void play(String audioType, String fileName) {if(audioType.equalsIgnoreCase("mp3")){System.out.println("Playing mp3 file. Name: " + fileName);}}
}
适配器模式示例:
interface MediaPlayer {void play(String audioType, String fileName);
}interface AdvancedMediaPlayer {void playVlc(String fileName);void playMp4(String fileName);
}class VlcPlayer implements AdvancedMediaPlayer {@Overridepublic void playVlc(String fileName) {System.out.println("Playing vlc file. Name: " + fileName);}@Overridepublic void playMp4(String fileName) {}
}class MediaAdapter implements MediaPlayer {AdvancedMediaPlayer advancedMusicPlayer;public MediaAdapter(String audioType) {if(audioType.equalsIgnoreCase("vlc")){advancedMusicPlayer = new VlcPlayer();}}@Overridepublic void play(String audioType, String fileName) {if(audioType.equalsIgnoreCase("vlc")){advancedMusicPlayer.playVlc(fileName);}}
}
7. 总结
特性 | 面向接口的编程 | 适配器模式 |
---|---|---|
核心目标 | 提高灵活性和解耦,通过接口实现行为抽象 | 通过适配器将不兼容的接口转为目标接口 |
主要目的 | 实现代码的可扩展性和可替换性 | 解决接口不兼容的问题 |
应用场景 | 需要多种类实现相同接口时 | 需要集成不同接口(特别是现有接口)时 |
设计特点 | 定义统一的接口,多个类实现 | 使用适配器类将不同接口桥接为一个统一接口 |