问题
前面的时候,我已经在生产华为和苹果的手机了,实际上我不仅做手机的生产,还会做手机相关的配件,比如说耳机。我在生产华为和苹果手机之前,就已经提前制造了大量的圆孔耳机。奈何,华为和苹果产品更新换代太快,新版苹果和华为手机都不再使用圆孔耳机了,华为要用type-c的耳机,苹果用lightning口耳机。这不就是坑了我这个代工厂了,我这生产的大批耳机还没用呢,就要被淘汰了!
这时候,为了不至于亏损,至少要先把这批耳机卖掉之后再说,可是新款手机都不支持圆孔耳机,这怎么办呢?那就需要我们强大的适配器了!通过适配器将通过type-c口传输来数据转成圆孔耳机接受的信号,那就可以继续使用圆孔耳机听音乐了!这就是适配器模式的作用:将输入的数据格式转换成处理者可处理的数据格式
实现
既然确定要转换器的了,那我们就来实现吧。首先我们给之前的华为和苹果手机加上听音乐功能吧, 要听音乐的话,就得给他们配上适配器和圆孔耳机才行。
public interface Mobile {
/**
* 玩手机
*/
void play();
void listenMusic();
}
public class AppleMobile implements Mobile {
private LightningAdapter adapter;
private RoundHoleHeadset headset;
public AppleMobile() {
adapter = new LightningAdapter();
headset = new RoundHoleHeadset();
}
public char[] getMusic() {
return new char[]{'a', 'b', 'c', 'd', 'e', 'f'};
}
@Override
public void play() {
System.out.println("i am playing apple mobile");
}
@Override
public void listenMusic() {
headset.listenMusic(adapter.transfer(getMusic()));
}
}
public class HuaweiMobile implements Mobile {
private TypeCAdapter adapter;
private RoundHoleHeadset headset;
public HuaweiMobile() {
adapter = new TypeCAdapter();
headset = new RoundHoleHeadset();
}
public int[] getMusic() {
return new int[]{1, 2, 3, 4, 5, 6, 7};
}
@Override
public void play() {
System.out.println("i am playing huawei mobile");
}
@Override
public void listenMusic() {
headset.listenMusic(adapter.transfer(getMusic()));
}
}
我们再来看一下适配器和耳机
public class RoundHoleHeadset {
public void listenMusic(String music) {
System.out.println("I am listening music: " + music);
}
}
public class LightningAdapter {
/**
* Lightning转换器是把苹果手机传来的
* char[]转为圆孔耳机可识别的string
*
* @param digits digits
* @return String
*/
public String transfer(char[] digits) {
System.out.println("type c transfer chars to string");
StringBuilder builder = new StringBuilder();
for (char temp: digits) {
builder.append(temp);
}
return builder.toString();
}
}
public class TypeCAdapter {
/**
* type-c转换器是把华为手机传来的
* int[]转为圆孔耳机可识别的string
*
* @param digits digits
* @return String
*/
public String transfer(int[] digits) {
System.out.println("type c transfer digits to string");
StringBuilder builder = new StringBuilder();
for (int temp: digits) {
builder.append(temp);
}
return builder.toString();
}
}
这样的话,我们就可以来听音乐了
public static void main(String[] args) {
AppleMobile appleMobile = new AppleMobile();
appleMobile.listenMusic();
HuaweiMobile huaweiMobile = new HuaweiMobile();
huaweiMobile.listenMusic();
}
执行结果:
type c transfer chars to string
I am listening music: abcdef
type c transfer digits to string
I am listening music: 1234567
我们通过数据格式的不同来模拟华为和苹果手机耳机孔的不同,由结果即可看出我们分别做了两个适配器来分别适配华为和苹果手机,并且可以播放音乐,完美!耳机又能卖出去了。
应用场景
适配器模式在实际生活和开发过程中应用都非常广。再举几个例子,比如:去过香港的朋友可能会知道岘港的插头和内地是不一样的,比如我去香港,想要给手机充电的话,就得买一个插头的适配器;再比如在家里,想要电脑接投影仪播放电影的时候,发现投影仪只支持vga,而你的电脑只支持hdmi,那么就需要vga转hdmi的转换器了;如果做过Android开发的话,应该对RecyclerView并不陌生,而其绘制item的方式也是通过Adapter的方式实现的。
总的来说,适配器模式出现的原因就是
- 一个系统原先只支持某种特定数据格式的处理,但后来呢,需要处理各种不同类型的数据,那么只好在前面加上适配器,将各种类型数据转成特定数据后,再交付给系统处理。
- 原本两个独立的系统,因为某种需求,需要进行交互,但是呢A系统传出的数据是xml格式,但是B系统只接收gson格式,那么在中间增加适配器,将数据格式进行转换。
总结
适配器模式的优点非常明显,无需修改目标类和适配者类的代码,就可以完成两个类之间的关联,并且将两个类解耦了,符合单一职责和开闭原则!缺点呢,就是若过度使用适配器模式,会使系统变得复杂和臃肿。适配器模式更适用于已经比较成熟和完善的项目,而新创建的项目可能直接改代码更为方便!