前言
适配器模式(Adapter Pattern),当你存在一个类,但是这个类不能拿来直接使用,必须要用适配方式。把一个类的接口变换成客户端所期待的另一种接口
实例代码
比如:你去香港旅游,跑去买了个iphone,结果发现是三角插座,国内不能使用,解决办法有两种:
1)重新买一个插头 2)买一个转换器即可
代码如下:
英标插头-三脚
/**
* @Description 英标插头 3脚
* @Date 2017/7/2 21:51
* @Since v1.7
* @Autor Nick
*/
public interface EnPluginInterface {
void chargeWith3Pins();
}
/**
* @Description
* @Date 2017/7/2 21:51
* @Since v1.7
* @Autor Nick
*/
public class EnPlugin implements EnPluginInterface {
@Override
public void chargeWith3Pins() {
System.out.println("charge with EnPlugin");
}
}
国标插头-2脚
/**
* @Description 国标插头 2脚
* @Date 2017/7/2 21:43
* @Since v1.7
* @Autor Nick
*/
public interface CnPluginInterface {
void chargeWith2Pins();
}
/**
* @Description
* @Date 2017/7/2 21:44
* @Since v1.7
* @Autor Nick
*/
public class CnPlugin implements CnPluginInterface {
//充电
@Override
public void chargeWith2Pins() {
System.out.println("charge with CnPlugin");
}
}
在家里充电只能使用2脚插头
/**
* @Description 在国内充电
* @Date 2017/7/2 21:45
* @Since v1.7
* @Autor Nick
*/
public class Home {
private CnPluginInterface cnPlugin;
public Home() {
}
public Home(CnPluginInterface cnPlugin) {
this.cnPlugin = cnPlugin;
}
public void setPlugin(CnPluginInterface cnPlugin) {
this.cnPlugin = cnPlugin;
}
//充电
public void charge() {
//国标充电
cnPlugin.chargeWith2Pins();
}
}
家里使用2脚测试
/**
* @Description
* @Date 2017/7/2 22:13
* @Since v1.7
* @Autor Nick
*/
public class HomeTest {
public static void main(String[] args) {
CnPluginInterface cnPlugin = new CnPlugin();
Home home = new Home(cnPlugin);
home.charge();
}
}
家里就是不能使用三脚插头,怎么办?这时候需要有一个适配器来适配
/**
* @Description
* @Date 2017/7/2 21:52
* @Since v1.7
* @Autor Nick
*/
public class PluginAdapter implements CnPluginInterface {
private EnPluginInterface enPlugin;
public PluginAdapter(EnPluginInterface enPlugin) {
this.enPlugin = enPlugin;
}
@Override
public void chargeWith2Pins() {
enPlugin.chargeWith3Pins();
}
}
拿转接器过来一试,发现果然可以充电了
/**
* @Description
* @Date 2017/7/2 22:13
* @Since v1.7
* @Autor Nick
*/
public class AdapterTest {
public static void main(String[] args) {
EnPluginInterface enPluginInterface = new EnPlugin();
Home home = new Home();
PluginAdapter pluginAdapter = new PluginAdapter(enPluginInterface);
home.setPlugin(pluginAdapter);
home.charge();
}
}
Java中用了大量的适配器
以InputStreamReader和OutputStreamWriter类为例。
InputStreamReader和OutputStreamWriter类分别继承了Reader和writer接口,但是要创建他们的对象必须在构造函数中传入一个InputStream和OutputStream的实例,InputStreamReader和OutputStreamWriter类的作用也就是将InputStream和OutputStream适配到Reader和Writer。
适配器是InputStreamReader,源角色是InputStream代表的实例对象,目标接口就是Reader类。
InputStream:得到的是字节输入流,InputStream.read("filename")之后,得到字节流
Reader:读取的是字符流
InputStreamReader:从字节到字符的桥梁。InputStreamReader(InputStream.read("filename"));
reader.read(InputStreamReader(InputStream in));便可从字节变为字符,打印显示了。
java.io.Reader 和 java.io.InputStream 组成了Java 输入类。
Reader 用于读入16位字符,也就是Unicode 编码的字符;而 InputStream 用于读入 ASCII 字符和二进制数据。
Reader支持16位的Unicode字符输出,
InputStream支持8位的字符输出。
Reader和InputStream分别是I/O库提供的两套平行独立的等级机构,
适配器种类
适配器其实有两种:1)类适配器,针对特定的某个类 2)面向对象的适配器
类适配器
场景:人去应聘工作,人会英语和中文,岗位的要求是要会英语、中文、法语,我的目的是要让这个人去干这份工作
public class Person {
private String name;
private String sex;
private int age;
public void speakChinese(){
System.out.println("I can speak Chinese!");
}
public void speakEnglish(){
System.out.println("I can speak English!");
}
...//以下省略成员变量的get和set方法
}
//目标接口
public interface Job {
public abstract void speakChinese();
public abstract void speakEnglish();
public abstract void speakFrench();
}
//适配器代码
public class Adapter extends Person implements Job{
public void speakFrench() {
}
}
适配器在这个岗位要求,只能为人服务
对象适配器
针对对象适配器,如果也要适配这个工作,对象的适配器模式,把“源”作为一个构造参数传入适配器,然后执行接口所要求的方法。这种适配模式可以为多个源进行适配。
public class Adapter implements Job {
Person person;
public Adapter(Person person) {
this.person = person;
}
public void speakEnglish() {
person.speakEnglish();
}
public void speakJapanese() {
person.speakJapanese();
}
//new add
public void speakFrench() {
}
}
默认适配器
一件事物,标准的属性有A、B、C,但是有个特例,只有A;
如:如果我说 和尚都不喝酒、不吃肉、梯度,你认同吧?
//和尚接口
public interface Monk {
public void notDrink();
public void notEatMeat();
public void tonsure();
}
实例:鲁智深,鲁智深是不是和尚?答案是的。鲁智深梯度了,但是鲁智深喝酒吃肉?我可以建一个花和尚的接口,但是我不想这么做,我想让鲁智深也实现Monk这个接口,又不想让他管不喝酒、不吃肉的戒律
引入抽象类
public abstract class AbstractMonk implement Monk {
public void notDrink() {}
public void notEatMeat() {}
public void tonsure() {}
}
花和尚
public class Luzhishen extends AbstractMonk {
@Override
public void tonsure() {
System.out.println("我是鲁智深,我剃度了");
}
}
应用场景总结
- 适配器对象实现原有接口
- 适配器对象组合一个实现新接口的对象(这个对象也可以不实现一个接口,只是一个单纯的对象)
- 对适配器原有接口方法的调用被委托给新接口的实例的特定方法