设计模式之适配器模式

来源:互联网 发布:淘宝剩余时间 编辑:程序博客网 时间:2024/06/05 20:33

前言

适配器模式(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接口,但是要创建他们的对象必须在构造函数中传入一个InputStreamOutputStream的实例,InputStreamReader和OutputStreamWriter类的作用也就是将InputStreamOutputStream适配到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("我是鲁智深,我剃度了");    }}

应用场景总结

  • 适配器对象实现原有接口
  • 适配器对象组合一个实现新接口的对象(这个对象也可以不实现一个接口,只是一个单纯的对象)
  • 对适配器原有接口方法的调用被委托给新接口的实例的特定方法