适配器模式就好像是 作为两个不兼容的接口之间的桥梁。
简单打个比方。美国电器 110V,中国 220V,就要有一个适配器将 110V 转化为 220V。适配器的概念就可以这么理解。
参考链接:http://www.runoob.com/design-pattern/adapter-pattern.html
为什么将外观模式也放进来呢,外观模式主要做的就是 简化接口,将一个或数个类的复杂的一切都隐藏在背后,只显露出一个干净美好的外观。
参考链接:http://www.runoob.com/design-pattern/facade-pattern.html
理论介绍
适配器模式: 将一个类的接口,转换成客户期待的另一个接口。适配器让原来接口不兼容的类可以合作无间。
客户使用适配器的过程如下:
- 客户通过目标接口调用适配器的方法对适配器发出请求
- 适配器使用被适配者接口把请求转换成被适配者的一个或多个调用接口
- 客户接收到调用的结果,但并未察觉这一切是适配器在起转换作用。
外观模式: 提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。
应用场景
- 系统需要使用现有的类,而此类的接口不符合系统的需要
- 想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有一致的接口
- 通过接口转换,将一个类插入另一个类系中。(比如老虎和飞禽,现在多了一个飞虎,在不增加实体的需求下,增加一个适配器,在里面包容一个虎对象,实现飞的接口
代码实现参考
背景:我们有一个 MediaPlayer 接口和一个实现了 MediaPlayer 接口的实体类 AudioPlayer。默认情况下,AudioPlayer 可以播放 mp3 格式的音频文件。
我们还有另一个接口 AdvancedMediaPlayer 和实现了 AdvancedMediaPlayer 接口的实体类。该类可以播放 vlc 和 mp4 格式的文件。
我们想要让 AudioPlayer 播放其他格式的音频文件。为了实现这个功能,我们需要创建一个实现了 MediaPlayer 接口的适配器类 MediaAdapter,并使用 AdvancedMediaPlayer 对象来播放所需的格式。
AudioPlayer 使用适配器类 MediaAdapter 传递所需的音频类型,不需要知道能播放所需格式音频的实际类。
1.为媒体播放器和更高级的媒体播放器创建接口。
package adapter_pattern;
public interface MediaPlayer {
void play(String audioType, String fileName);
}
package adapter_pattern;
public interface AdvanceMediaPlayer {
void playVlc(String fileName);
void playMp4(String fileName);
}
2.创建实现了AdvancedMediaPlayer接口的实体类
package adapter_pattern;
public class VlcPlayer implements AdvanceMediaPlayer {
@Override
public void playVlc(String fileName) {
System.out.println("Playing a vlc file: " + fileName);
}
@Override
public void playMp4(String fileName) {
throw new IllegalArgumentException("wrong type" + fileName);
}
}
package adapter_pattern;
public class Mp4Player implements AdvanceMediaPlayer {
@Override
public void playVlc(String fileName) {
throw new IllegalArgumentException("wrong type" + fileName);
}
@Override
public void playMp4(String fileName) {
System.out.println("Playing mp4 file: " + fileName);
}
}
3.创建实现了 MediaPlayer 接口的适配器类。
package adapter_pattern;
public class MediaAdapter implements MediaPlayer{
AdvanceMediaPlayer advanceMediaPlayer;
public MediaAdapter(String audioType) {
if (audioType.equalsIgnoreCase("vlc"))
advanceMediaPlayer = new VlcPlayer();
else if (audioType.equalsIgnoreCase("mp4"))
advanceMediaPlayer = new Mp4Player();
}
@Override
public void play(String audioType, String fileName) {
if (audioType.equalsIgnoreCase("vlc"))
advanceMediaPlayer.playVlc(fileName);
else if (audioType.equalsIgnoreCase("mp4"))
advanceMediaPlayer.playMp4(fileName);
}
}
4.创建实现了 MediaPlayer 接口的实体类。
package adapter_pattern;
public class AudioPlayer implements MediaPlayer{
MediaAdapter mediaAdapter;
@Override
public void play(String audioType, String fileName) {
if (audioType.equalsIgnoreCase("mp3"))
System.out.println("Playing mp3 file: " + fileName);
else if (audioType.equalsIgnoreCase("vlc")
|| audioType.equalsIgnoreCase("mp4")){
mediaAdapter = new MediaAdapter(audioType);
mediaAdapter.play(audioType, fileName);
}
else throw new IllegalArgumentException("wrong type: " + audioType);
}
}
5.使用 AudioPlayer 来播放不同类型的音频格式
package adapter_pattern;
public class PlayerTest {
public static void main(String[] args) throws InterruptedException {
AudioPlayer audioPlayer = new AudioPlayer();
audioPlayer.play("mp3", "lalalala");
audioPlayer.play("mp4", "bubububu");
audioPlayer.play("vlc", "kukukuku");
Thread.sleep(100);
audioPlayer.play("doc", "liaoliaoliaoliao");
}
}
测试结果展示:
Playing mp3 file: lalalala
Playing mp4 file: bubububu
Playing a vlc file: kukukuku
Exception in thread "main" java.lang.IllegalArgumentException: wrong type: doc
at adapter_pattern.AudioPlayer.play(AudioPlayer.java:16)
at adapter_pattern.PlayerTest.main(PlayerTest.java:12)
补充
设计原则:“最少知识”原则(也叫“德墨忒尔”法则)。
只和你的密友谈话。
换句话说,如何不要赢得太多的朋友和影响太多的对象。
是不是有点抽象?我觉得是的。
这个原则提供了一些方针:就任何对象而言,在该对象的方法内,我们只应该调用属于以下范围的方法:
- 该对象本身
- 被当作方法的参数而传递进来的对象
- 此方法所创建或实例化的任何对象
- 对象的任何组件
虽然原则提供了方针,但在采用原则之前,必须全盘考虑所有的因素,原则的应用都应该在有帮助的时候才遵守。