likes
comments
collection
share

面试官:了解“适配器”模式吗,有哪些使用方法?

作者站长头像
站长
· 阅读数 11

适配器模式是一种结构型设计模式,用于将一个类的接口转换成客户端所期望的另一种接口。适配器模式允许不兼容的接口之间进行协作。它可以将现有代码与外部库、框架或API集成起来,而无需修改已有代码。

适配器模式包含以下几个角色:

  1. 目标接口(Target Interface):客户端所要求的接口,也就是客户端想要使用的接口类型。

  2. 适配器(Adapter):将现有类(即被适配者)的接口转换成目标接口的类,实现目标接口,并持有被适配者的实例。

  3. 被适配者(Adaptee):需要被适配的类,提供了常规的方法调用。

  4. 客户端(Client):使用目标接口的对象。

适配器模式的应用场景比较广泛,特别是在与第三方库或框架集成时,由于外部库、框架或API可能具有不同的接口,因此需要使用适配器模式来使这些不兼容的接口之间进行协作。同时,在系统升级或重构时,适配器模式也可以帮助我们保留原有代码的功能。

总之,适配器模式是一种结构型设计模式,用于将不兼容的接口转换成客户端所需要的接口类型,让客户端能够更加方便地使用已有代码。

以下是一个简单的Java代码示例,演示了如何使用适配器模式将一个接口转换成客户端需要的另一个接口:

// 客户端需要的目标接口
interface Target {
    void request();
}

// 需要被适配的Adaptee接口
class Adaptee {
    public void specificRequest() {
        System.out.println("Adaptee specific request.");
    }
}

// 适配器Adapter,将Adaptee接口转换成Target接口
class Adapter implements Target {
    private Adaptee adaptee;

    public Adapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    @Override
    public void request() {
        System.out.println("Adapter request.");
        adaptee.specificRequest();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Adaptee adaptee = new Adaptee();
        Target target = new Adapter(adaptee);
        target.request();
    }
}

在上述示例代码中,Client需要使用的Target接口与现有的Adaptee接口不兼容,因此需要创建一个Adapter适配器来转换接口。Adapter实现了Target接口,并持有一个Adaptee对象,通过调用Adaptee的specificRequest()方法来实现Target接口的request()方法。这样,Client就可以使用Target接口了,而不用关心Adaptee接口的具体实现。

注解版本

以下是一个使用@Autowired注解来引入适配器对象的Java代码示例:

// 现有的非兼容接口
interface NonCompatibleInterface {
    void doSomething();
}

// 第三方库中提供的类
@Component // 将ThirdPartyClass声明为Spring组件
class ThirdPartyClass {
    public void doOtherThing() {
        System.out.println("Third party library do other thing.");
    }
}

// 适配器Adapter,将ThirdPartyClass适配为NonCompatibleInterface
@Component // 将Adapter声明为Spring组件
class Adapter implements NonCompatibleInterface {
    @Autowired // 自动注入ThirdPartyClass对象
    private ThirdPartyClass thirdParty;

    @Override
    public void doSomething() {
        System.out.println("Adapter do something.");
        thirdParty.doOtherThing();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        NonCompatibleInterface adapter = context.getBean(Adapter.class);
        adapter.doSomething();
    }
}

// Spring配置类
@Configuration
@ComponentScan(basePackages = {"com.example.adapter"}) // 扫描Adapter和ThirdPartyClass所在的包
public class AppConfig {
}

在上述示例代码中,我们使用Spring框架来管理和注入适配器对象和被适配的对象。使用@Autowired注解自动注入ThirdPartyClass对象,并在Adapter中使用该对象来实现NonCompatibleInterface接口的方法。客户端代码中,我们通过Spring容器获取Adapter对象,并调用其doSomething()方法。

常见的实践场景:

如果A接口有多个方法,而B类只需要其中的一部分方法,我们可以将B类注入到A类中,并在A类中实现B接口的方法,从而只处理需要的接口方法。这样做既可以避免B类实现整个A接口,又可以让B类的功能得以利用。

以下是一个Java代码示例,演示了如何将B类注入到A类中,并实现B接口的部分方法:

// A接口
interface A {
    void method1();
    void method2();
    void method3();
}

// B接口
interface B {
    void method1();
    void method3();
}

// B类
@Component // 将BImpl声明为Spring组件
class BImpl implements B {
    @Override
    public void method1() {
        System.out.println("BImpl.method1");
    }

    @Override
    public void method3() {
        System.out.println("BImpl.method3");
    }
}

// A类
@Component // 将AImpl声明为Spring组件
class AImpl implements A {
    @Autowired // 自动注入B对象
    private B b;

    @Override
    public void method1() {
        b.method1();
    }

    @Override
    public void method2() {
        System.out.println("AImpl.method2");
    }

    @Override
    public void method3() {
        b.method3();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        A a = context.getBean(A.class);
        a.method1(); // 调用B接口的method1实现
        a.method3(); // 调用B接口的method3实现
    }
}

// Spring配置类
@Configuration
@ComponentScan(basePackages = {"com.example.adapter"}) // 扫描AImpl和BImpl所在的包
public class AppConfig {
}

通过将B类注入A类中,并实现B接口的部分方法,我们可以避免B类实现整个A接口,同时又能够利用B类的功能。

以上是常用的场景,就是很简单的操作,不要认为适配器模式有多难,从概念上理解的话,学习成本高,易忘记。

总之,适配器模式是一种常用的设计模式,可以帮助我们兼容新旧代码、兼容不同接口等场景。在实际开发中,我们需要根据具体需求选择合适的适配器类型,并实现相应的适配器类来完成接口转换。

欢迎关注公众号:程序员的思考与落地

公众号提供大量实践案例,Java入门者不容错过哦,可以交流!!