一起来学习设计模式:适配器模式
前言:
学习设计模式是为了更好地用面向对象的思维去设计,去编写我们的代码,也为了我们去看源码,学习别人优秀的设计做好准备;写的一些东西都是自己的一些笔记,大家都可以去网上搜相关的博客来学习~欢迎各位交流
1.适配器概念
适配器模式(Adapter Pattern)是两个八竿子打不着的接口之间的桥梁。它结合了两个接口的独立功能。这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。比如我们自己买的显示屏,想连到电脑上有HDMI这种转换线等等。这里的转换线就是一个适配器,让我们的电脑和显示器可以连在一起。
- 作用:将一个类的接口转换成我们想要的接口。可以使两个不相容的接口一起工作~
- 在软件设计中解决的问题:将一些本来存在的功能,接口等放到新环境中
- 实现方式:依赖或者继承
- 优点:让任何两个没有相关联的类一起运行;提高了类的复用性;
- 缺点:过多使用,可读性不高,比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,
因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。写太多,估计会被后面的维护人员打~哈哈哈。咱们写代码不能为了装逼而装逼,而是解决实际问题 - 啥时候用:一个正在运行的系统,如果你想修改一下。比如说:某个播放器软件,只能只能播放MP4后缀的,你想播放.avi了。这个时候可以考虑一下用适配器模式~
2.实现
image.png分析:
从上面的图我们可以分析:假设现在我们有两个接口,分别是AdancedMediaPlayer和MediaPlayer,他们分别都有自己的实现类,现在我们要通过一个适配器把这些功能都统一起来管理
按照上面的UML图
我们可以用代码做如下实现:
step1:
创建一个AdancedMediaPlayer 接口和他的实现类
public interface AdancedMediaPlayer {
void playVlc(String fileName);
void playMp4(String fileName);
}
public class MP4Player implements AdancedMediaPlayer {
@Override
public void playVlc(String fileName) {
//啥也不做
}
@Override
public void playMp4(String fileName) {
System.out.println("Playing mp4 file. Name: "+ fileName);
}
}
step2:
创建适配器,创建一个MediaPlayer接口,并利用组合的方式,将AdancedMediaPlayer 依赖进来
public interface MediaPlayer {
void play(String audioType, String fileName);
}
public class MediaAdapter implements MediaPlayer {
AdancedMediaPlayer advancedMusicPlayer;
public MediaAdapter(String audioType) {
//放进来适配
if(audioType.equalsIgnoreCase("vlc") ){
advancedMusicPlayer = new VclPlayer();
} else if (audioType.equalsIgnoreCase("mp4")){
advancedMusicPlayer = new MP4Player();
}
}
@Override
public void play(String audioType, String fileName) {
if(audioType.equalsIgnoreCase("vlc")){
advancedMusicPlayer.playVlc(fileName);
}else if(audioType.equalsIgnoreCase("mp4")){
advancedMusicPlayer.playMp4(fileName);
}
}
}
这里是比较重点的,因为就是这里利用了适配器模式
我们可以看到巧妙地利用构造方法和组合的方式,就可以把AdancedMediaPlayer 组合进来,从而可以在后面的代码中复用这些功能
step3:
创建MediaPlayer的实现类,在保证自己功能实现的情况下,引入适配器,从而可以调用适配器中的功能
public class AudioPlayer implements MediaPlayer{
MediaAdapter mediaAdapter;
@Override
public void play(String audioType, String fileName) {
//播放MP3,本来接口存在的方法
if(audioType.equalsIgnoreCase("mp3")) {
System.out.println("Playing mp3 file. Name: "+ fileName);
}else if(audioType.equalsIgnoreCase("vlc")
|| audioType.equalsIgnoreCase("mp4")) {
//mediaAdapter 提供了播放其他文件格式的支持,这里利用适配器使用其他功能
mediaAdapter = new MediaAdapter(audioType);
mediaAdapter.play(audioType, fileName);
} else{
System.out.println("Invalid media. "+
audioType + " format not supported");
}
}
}
step4:
具体测试类:
public class AdapterPatternDemo {
public static void main(String[] args) {
AudioPlayer audioPlayer = new AudioPlayer();
audioPlayer.play("mp3", "1.mp3");
audioPlayer.play("mp4", "2.mp4");
audioPlayer.play("vlc", "3.vlc");
audioPlayer.play("avi", "4.avi");
}
}
结果:
教程入口:
www.coder520.com 码码在线
http://www.runoob.com/design-pattern/adapter-pattern.html 菜鸟教程
3.总结:
其实从上面的展示来看,就是将两个相对独立的功能,放在一块实现,当我们具体调用的时候便于我们一定的扩展,想想如果我们没用适配器模式的话,具体的程序入口代码块那就要每次都要new 一个对应的对象出来,下次如果这个对象不用了,我们又得找到这一段代码把它注释掉或者删掉;很麻烦,代码量上去的话,找这一段代码的时间,我可能都已经写下一个功能。因此,总的来说适配器设计模式还是有利于我们的。但是,还是要提一句,用的不要泛滥,不然明明是调用A接口功能的,又有B功能的存在,如果功能点越来越多,你还往里面放的话,那代码可阅读性和维护都很麻烦~
引用一句比较流行的话:可以用但是没必要~