不学无数—适配器模式

适配器模式

Posted by 不学无数 on September 24, 2018

适配器模式

智者千虑必有一失,愚者千虑必有一得

在我们开发过程中也会经常碰到一些给原有的系统加一些功能,所以不管前期我们呢可行性、需求分析和系统设计处理的多好,随着时间的推移,总会出一些“意外”。因此我们该如何处理掉这些“意外”呢?聪明的程序员们就想到了许多的补救模式,其中适配器模式就是补救模式中的一种。这种模式可以能够让你从因为业务的快速迭代而引发代码改变的烦恼中解脱出来。

适配模式的定义

将一个类的接口变换成客户端所期待的另一种接口,从而使原本因为接口不匹配而无法在一起工作的两个类能够一起工作

适配器模式有三个角色

  • Source:需要被适配的接口或者对象,你想把谁转换成目标角色,那么这个“谁”就是Source角色
  • Target:需要得到的接口或者对象,即适配完Source得到的接口或者对象,我们所期望的接口
  • Adapter:适配器,协调Source和Target使两个能够一起工作。通过继承或者是类关联的方式

继承适配器

适配器模式有两种体现形式,一种是通过继承来表现,一种是通过关联对象来表现,下面给演示下继承表现的适配器。

适配器模式类图

下面我们写一个简单的适配器模式的例子,如下所示

Target接口代码

interface Target{
    public void request();
}

实现了Target接口的类

class RealTarget implements Target{
    @Override
    public void request() {
        System.out.println("I am Target");
    }
}

Source源目标类

class Source{
    public void doSomething(){
        System.out.println("I am Source");
    }
}

接下来核心的角色要出现了就是Adapter

class Adapter extends Source implements Target{
    @Override
    public void request() {
        super.doSomething();
    }
}

接下来我们可以进行调用试试

public class AdapterTest {
    public static void main(String[] args) {
        Target target = new RealTarget();
        target.request();
        Target target2 = new Adapter();
        target2.request();
    }
}

打印如下

I am Target
I am Source

对象适配器

我们上面使用的是通过继承来使用适配器模式,还有一种做法就是将原有的继承关系变更为关联关系就可以了。

对象适配器和类适配器的区别在于:类适配器是通过继承来表现的,而对象适配器是对象的合成关系,也可以说是类的关联关系,这是两者的根本区别。两个都会在项目中用到,由于对象适配器是通过类间的关联关系进行耦合的,因此在设计的时候就比较灵活。而类适配器只能通过覆写源角色的方法进行扩展。因此在实际项目中,对象适配器的使用场景比较多。

我们还是先来看一下对象适配器的类图如下

对象适配器类图

然后写一个通用的例子

现在接口Target

interface Target2{
    public void printSource1();
    public void printSource2();
}

然后有Adapter

class Adapter implements Target{

    private Source1 source1;
    private Source2 source2;

    public Adapter(){
        source1 = new Source1();
        source2 = new Source2();
    }

    @Override
    public void printSource1() {
        source1.print();
    }

    @Override
    public void printSource2() {
        source2.print();
    }

}

然后两个Source

class Source1{
    public void print(){
        System.out.println("I am Source1");
    }
}

class Source2{
    public void print(){
        System.out.println("I am Source2");
    }
}

然后进行调用如下

public static void main(String[] args) {
    Target2 target2 = new Adapter2();
    target2.printSource1();
    target2.printSource2();
}

打印如下

I am Source1
I am Source2

这样在以后增加了需求以后,只需要重新写适配器即可,上层代码不用动。

适配器的优点

  • 适配器模式可以让两个没有任何关系的类在一起运行,只要适配器这个角色即可。
  • 增加了类的透明性:我们访问的是Target目标角色,但是具体的实现都是委托给了源角色,而这些对高层次的模块是透明的,也是它不需要关心的。
  • 提高了类的复用:源角色在原有的系统中还是能够继续使用,而在目标角色中也可以充当新的角色。
  • 灵活性好:如果某一天突然一个适配器不需要了,那么只要删除即可,基本上就类似于一个灵活的构件,想用就用。

适配器模式的使用场景

适配器应用的场景只需要记住一点就够了:当你有动机修改一个已经投产中的接口时,适配器模式是最适合你的模式。比如系统扩展了,需要使用一个已有或者是新建的类,但是这个类又不符合系统的接口,怎么办?这时候就可以使用适配器模式。

参考文章