大话设计模式:适配器模式

/ 大话设计模式 / 0 条评论 / 391人围观

接口适配器模式

接口适配器也是默认的适配器模式

说明:

有一个接口中有许多的方法,我想使用这个接口的话,我需要全部实现里面的方法,但我只想用其中的某几个方法,这时候就需要一个适配器

举例:

它用于实现下面的接口,但是所有的方法都是空方法,这样,我们就可以转而定义自己的类来继承下面这个类即可。

繁琐的接口:

/**
 * description 文件管理监听接口
 *
 * @author 70KG
 * @date 2018/8/20
 */
public interface FileManagerListener {

    void onStart(final File observer);

    void onDirectoryCreate(final File directory);

    void onDirectoryChange(final File directory);

    void onDirectoryDelete(final File directory);

    void onFileCreate(final File file);

    void onFileChange(final File file);

    void onFileDelete(final File file);

    void onStop(final File observer);

}

适配器:

/**
 * description 适配器实现
 *
 * @author 70KG
 * @date 2018/8/20
 */
public class FileAdapter implements FileManagerListener {

    @Override
    public void onStart(File observer) {

    }

    @Override
    public void onDirectoryCreate(File directory) {

    }

    @Override
    public void onDirectoryChange(File directory) {

    }

    @Override
    public void onDirectoryDelete(File directory) {

    }

    @Override
    public void onFileCreate(File file) {

    }

    @Override
    public void onFileChange(File file) {

    }

    @Override
    public void onFileDelete(File file) {

    }

    @Override
    public void onStop(File observer) {

    }
}

自定义的类:

/**
 * description
 *
 * @author 70KG
 * @date 2018/8/20
 */
public class FileManager extends FileAdapter {

    @Override
    public void onFileCreate(File file) {

        // do something

    }

    @Override
    public void onFileDelete(File file) {

        // do something

    }

}

对象适配器模式

《Head First 设计模式》中的一个例子:我们需要一只鸭,但是我们只有一只鸡,如何让这只鸡冒充鸭,并将它作为鸭来使用呢?

  1. 首先定义好鸭和鸡的接口和实现类
public interface Duck {
    public void quack(); // 鸭的呱呱叫
      public void fly(); // 飞
}

public interface Cock {
    public void gobble(); // 鸡的咕咕叫
      public void fly(); // 飞
}

public class WildCock implements Cock {
    public void gobble() {
        System.out.println("咕咕叫");
    }
      public void fly() {
        System.out.println("鸡也会飞哦");
    }
}
  1. 定义鸭的适配器

首先,这个适配器肯定需要 implements Duck,这样才能当做鸭来用,构造方法中需要一个鸡的实例,此类就是将这只鸡适配成鸭来用,实现鸭的呱呱叫方法,但内部其实是一只鸡的咕咕叫

/**
 * description 用来适配鸭的适配器
 *
 * @author 70KG
 * @date 2018/8/20
 */
public class CockAdapter implements Duck {

    private Cock cock;

    public CockAdapter() {

    }

    public CockAdapter(Cock cock) {
        this.cock = cock;
    }

    // 在鸭子叫的方法中,调用鸡叫,从而实现了鸭子也能学鸡叫,哈哈
    @Override
    public void quack() {
        cock.gobble();
    }

    // 共有的方法,不用适配
    @Override
    public void fly() {
        cock.fly();
    }
    
}
  1. 让鸡来冒充鸭

首先,得先有一只野鸡,然后将野鸡作为参数传入实现Duck接口的适配器类中,从而实现了冒充功能。

/**
 * description
 *
 * @author 70KG
 * @date 2018/8/20
 */
public class MainTest {

    // 正常的多态
    @Test
    public void m1() {
        Cock cock = new WildCock();
        cock.gobble();
        cock.fly();
    }

    // 通过适配器,来让鸭子学鸡叫
    @Test
    public void m2() {
        // 有一只野鸡
        Cock wildCock = new WildCock();
        // 将野鸡适配成鸭子
        Duck duck = new CockAdapter(wildCock);
        // 这时候的鸭子竟然会咕咕叫,但其本质还是一只鸡,哈哈。
        duck.quack();
        duck.fly();
    }

}

类适配器模式

问题:手中有个ps2插头(就是老式鼠标键盘的那种圆形插头,好多针的那种,现在除了电竞还在用,因为这种传输可以轻松实现全键盘无冲,但基本已经淘汰)的设备,但是主机上只有usb插头的插口,怎么办呢?弄个转换器,将ps2插头转换成为USB插头就可以使用了。

举例:

PS2接口:

/**
 * description
 *
 * @author 70KG
 * @date 2018/8/20
 */
public interface Ps2 {

    void isPs2();

}

USB接口:

/**
 * description
 *
 * @author 70KG
 * @date 2018/8/20
 */
public interface Usb {

    void isUsb();

}

USB接口实现类(也就是现在的鼠标):

/**
 * description
 *
 * @author 70KG
 * @date 2018/8/20
 */
public class Usber implements Usb {

    @Override
    public void isUsb() {
        System.out.println("USB口");
    }

}

适配器(也就是现在的转接头):

/**
 * description
 *
 * @author 70KG
 * @date 2018/8/20
 */
public class Adapter extends Usber implements Ps2 {

    @Override
    public void isPs2() {
        // 调用usb的方法
        isUsb();
    }

}

测试类:

/**
 * description
 *
 * @author 70KG
 * @date 2018/8/20
 */
public class MainTest {

    @Test
    public void m1() {
        Ps2 p = new Adapter();
        p.isPs2();
    }

}

测试结果:

USB口

成功将PS2接口适配成USB接口

适配器模式和代理模式

比较这两种模式,其实是比较对象适配器模式和代理模式,在代码结构上,它们很相似,都需要一个具体的实现类的实例。但是它们的目的不一样,代理模式做的是增强原方法的活;适配器做的是适配的活,为的是提供“把鸡包装成鸭,然后当做鸭来使用”,而鸡和鸭它们之间原本没有继承关系。

使用场景

类适配器使用场景:

  1. 想要使用一个已经存在的类,但是它却不符合现有的接口规范,导致无法直接去访问,这时创建一个适配器就能间接去访问这个类中的方法。
  2. 我们有一个类,想将其设计为可重用的类(可被多处访问),我们可以创建适配器来将这个类来适配其他没有提供合适接口的类。

以上两个场景其实就是从两个角度来描述一类问题,那就是要访问的方法不在合适的接口里,一个从接口出发(被访问),一个从访问出发(主动访问)。

接口适配器使用场景:

  1. 想要使用接口中的某个或某些方法,但是接口中有太多方法,我们要使用时必须实现接口并实现其中的所有方法,可以使用抽象类来实现接口,并不对方法进行实现(仅置空),然后我们再继承这个抽象类来通过重写想用的方法的方式来实现。这个抽象类就是适配器。