Java设计模式(一) Adapter(适配器)模式及I/O实例引申

基本概念

适配器模式是一种补救模式,将一个类的接口转换成客户希望的另外一个接口。Adapter模式使原本由于接口不兼容而不能一起工作的类可以一起工作。是包装模式(对类或者对象进行包装)的一种,分为类适配器对象适配器,是从实现层面上划分。

这个模式中包含三种角色:

  • Target目标角色:该角色定义我们要将原接口转化为何种接口,也就是我们期望得到的接口(方便多态地使用)
  • Adaptee源角色:需要利用适配器进行包装的原接口
  • Adapter适配器:该模式的核心角色,具有将Adaptee包装为Target的职责

综上,我们能够知道该模式中各个角色的关系:

Adapter改变了Adaptee的接口,使Adaptee和Adapter的基类Target匹配。这样Client就可以把Adaptee当作Target类型来使用。(多态得以实现)

例讲Adapter的具体实现

类适配器的实现

我们规定一个情景,A公司要收购B公司,但是他们有两套接口不是很一致的人员管理系统,如下:

  • 首先我们给出A公司的接口和实现类(其实重要的只是接口)
interface MyEmployee{
    public String getName();
    public void setName(String name);
    public String getPosition();
    public void setPosition( String position );
    public String getAddress();
    public void setAddress( String address );
    public String getAge();
    public void setAge( String age );
}

实现类如下,给出实现,只是体现适配器能极大程度忽略内部实现细节。

class EmployeeA implements MyEmployee {//实现MyEmployee接口
    private String name;
    private String position;
    private String address;
    private String age;
//应该注意@override注释的必要性,能检查是否为有效的覆盖
    @Override
    public String getName() {
        return name;
    }

    @Override
    public void setName(String name) {
        this.name = name;
    }
 //TODO 同样的getter和setter
}
  • 然而我们的B公司的提供了完全不同的接口和实现方式(为了简单直接写在一起了…实际上接口和实现分开是有优势的),B公司将所有的信息存在了一个利用键值对对应的map中,好尴尬啊…适配器就应该在这时候出现进行补救。
class EmployeeB{
    private Map<String,String> basicInfo;

    public Map<String, String> getBasicInfo() {
        return basicInfo;
    }

    public void setBasicInfo(Map<String, String> basicInfo) {
        this.basicInfo = basicInfo;
    }
}

我们采用类适配器来解决这一问题,定义上类适配器应该继承原类,实现目标接口,这样能够达到获得源类的方法,并且采用目标接口的调用形式

class EmployeeAdapter extends EmployeeB implements MyEmployee {
    @Override
    public String getName() {
        return getBasicInfo().get("name");
    }

    @Override
    public void setName(String name) {
        Map<String,String> dic = getBasicInfo();
        String key = "name";
        dic.remove( key);
        dic.put( key , name );
    }
}

然后我们就可以利用MyEmployee接口同时操作两个公司的员工,并且可以实现多态需要达到的任何操作。

public class adapterEg {
    public static void main ( String [] args ){
        MyEmployee b = new EmployeeAdapter();
        MyEmployee a = new EmployeeA();
        //TODO 一系列操作
    }
}

对象适配器的实现

其实往往现实问题没有我们想象中的那般美好,公司经营出现问题的很多,重组的AB公司开始收购C公司,然而C公司活该倒闭,接口杂乱不堪…..将每个属性独立开来,因为Java不支持多继承(这并不是功能的缺失,而是对好的代码结构的一种保证)

class CName {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

class CAddress{
    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}
//TODO 诸如此类的重复代码,没必要赘述

我们可以采用委托的方式替代继承的方式,来到适配的效果

class AdapterC implements  MyEmployee{

    private CName cname;
    private CAddress address;
    //TODO 其他的过于赘余,不再多讲 
    AdapterC(){
        cname = new CName();
        address = new CAddress();
    }

    @Override
    public String getName() {
        return cname.getName();
    }

    @Override
    public void setName(String name) {
        cname.setName(name);
    }

也能够达到适配的效果,是不是很简单!!!!

适配器模式的优点

  • 能够让两个设计初期没有考虑公用一个接口的类,能够通过添加适配器补救
  • 增加了类的透明性,具体实现委托给了源角色,只提供统一的接口
  • 使一些类能够在新的设计中得到复用(可以通过适配解决接口不统一的问题)
  • 灵活性好,易拓展的同时也方便删改,因为只需要去掉适配器即可,耦合性低,是良好的设计

适配器模式的适用场景

在系统拓展时,为了使新的设计与旧的设计相适应而采取的模式,它不是为了解决还在处于开发阶段的问题,而是解决正在服役中的项目问题。

同作为包装模式,外观模式(Facade)与适配器模式的区别:

  • 在两个模式中都存在既有的类(也就是需要通过包装来适用某些功能的类)
  • Facade不需要适用多态行为,而adapter多数情况下是为了适应多态场景,如上述的场景
  • 动机上,Facade是为了简化接口,而Adapter尽管也希望接口尽量简单,但是是为了遵循一个已有的接口,即时这样失去了使用一个设计更加简洁的接口的可能。

总结如下表

item Facade Adapter
是否存在既有的类
是否要遵循某个接口
是否适应多态 可能
需要更简单的接口

Java I/O对适配器模式的使用

  • 最直接的就是InputStreamReader和OutputStreamWriter就是InputStream和OutputStream针对Reader和Writer接口的适配。
  • 比如InputStreamReader实现了Reader接口,并且持有了InputStream的引用(对象适配),通过StreamDecoder类间接持有,因为从byte到char需要编码。

鸡汤

  • 技术是为业务服务的,因此业务在日新月异变化的同时,也对技术提出了同样的要求
  • 在这种要求下,使用补救模式可以保证我们的系统在生命周期内能够稳定、可靠、健壮的运行,而适配器模式就是这样一个救世主,它通过把非本系统接口的对象包装成本系统可以接收的对象,从而简化了系统大规模变更的风险。
    ——《设计模式之禅》

你可能感兴趣的:(Java设计模式(一) Adapter(适配器)模式及I/O实例引申)