菜鸟教程链接:适配器模式
概念
适配器模式可以理解为通过不修改父类或接口的情况下,通过子类或实现类组合装载了所需扩展接口的适配器(或直接组合所需扩展接口)的方式,让原来的类或接口可以适配于客户端新的场景。该设计模式不应该应用于设计一个类的过程中,而应该在修改历史代码的过程中使用,使在不修改老代码的基础上扩展新的业务场景,体现了 复合大于继承 这一观点。
优缺点
优点:
- 提高了类的复用
- 灵活,透明
缺点:
- 可能会使类的定义与其运行时体现的功能不一致,系统复杂度提升
- 对原有的实现类有侵入
- 由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。
适用场景
对老代码做兼容性升级的场景
示例代码
原本的手机只有打电话和发短信功能,只需实现Phone的接口
public class MobilePhone implements Phone{
@Override
public void play(String type) {
if ("call".equals(type)){
this.call()
) else if {"message".equals(type)){
this.message()
}
}
}
智能机时代来临,我们手机扩展了播放音乐和视屏的功能,那么我们需要在原有类的基础上直接扩展这些功能吗?不需要,因为音乐和视屏都早已存在对应的实现类与接口了,比如mp3已经实现类MusicPlayer的接口,而TV实现了VedioPlayer的接口,我们只需要将这两个类聚合在一个Adaper类里面,然后再我们的MobilePhone里面注入这个Adaper,通过Adaper去调用这些方法。(个人觉得这里适配器其实无所谓是否实现Phone接口了)
public class MobilePhoneAdapter implements Phone{
private MusicPlayer mp3 = new Mp3();
private VedioPlay tv = new TV();
@Override
public void play(String type) {
if ("music".equals(type)){
mp3.music()
) else if {"vedio".equals(type)){
tv.vedio()
}
}
}
然后再将MobilePhoneAdaper注入到原有的MobilePhone里面,即可在原来的接口中聚合新的功能,这一点在某些场景非常重要。
public class MobilePhone implements Phone{
private MobilePhoneAdapter= new MobilePhoneAdaper();
@Override
public void play(String type) {
if ("call".equals(type)){
this.call()
) else if {"message".equals(type)){
this.message()
} else {
adapter.play(type)
}
}
}
如果我们在构造函数中做手法,甚至可以通过构造不同的适配器,让手机实现不同的功能;比如,我可以让播放音乐的功能由同样实现了MusicPlayer接口的mp4而不是mp3实现,即可通过传递接口来决定Adapter的成员变量,而MobilePhone中同理,此时代码成熟度更高了。
public class MobilePhoneAdapter implements Phone{
private MusicPlayer musicPlayer;
private VedioPlay vedioPlayer;
public MobilePhoneAdapter(MusicPlayer musicPlayer, VedioPlay vedioPlayer) {
this.musicPlayer = musicPlayer;
this.vedioPlayer = vedioPlayer;
}
@Override
public void play(String type) {
if ("music".equals(type)){
musicPlayer.music()
) else if {"vedio".equals(type)){
vedioPlayer.vedio()
}
}
}
public class MobilePhone implements Phone{
private MobilePhoneAdapter adapter;
public MobilePhone(MobilePhoneAdapter adapter) {
this.adapter =adapter;
}
@Override
public void play(String type) {
if ("call".equals(type)){
this.call()
) else if {"message".equals(type)){
this.message()
} else {
adapter.play(type)
}
}
}
使用时
public class TEST {
public void test(String type) {
MusicPlayer musicPlayer = new Mp4();
MobilePhoneAdapter adapter = new MobilePhoneAdapter (musicPlayer,new TV());
Phone phone = new MobilePhone(adapter);
phone.play("music");
}
}
也有说法直接用adapter去组合其他接口视作一个实现类,使用时直接调用adapter去执行play方法。单个人认为这种说法并不合适,不仅在adapter中要重复已有实现类的方法,也降低了类的扩展性和清晰结构,而且定义也更加模糊,你用手机玩游戏,而不是你在用手机里的模拟器玩游戏。