设计模式--适配器模式

96 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第22天,点击查看活动详情

适配器模式

适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。

这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能,也就是将适配器组合到不适配的类中,使用适配器做相应处理,达到适配的目的。

分类

  • 类的适配器模式
  • 对象的适配器模式
  • 接口的适配器模式

角色

  • 适配者(被适配的类)
  • 适配器(对两个不兼容的类进行适配)
  • 客户端

类的适配器模式

简介

核心思想就是:有一个Source类,待适配(待支持其他方法),目标接口就是Targetable,通过Adapter类将Source功能扩展到Targetable里。

实现

Source类:

public class Source {
    public void method01(){
        System.out.println("支持method01");
    }
}

TargetAble接口:

public interface TargetAble {
    /**
     * 方法名称必须和Source中的方法名称相同
     */
    void method01();
    /**
     * 目标接口需要适配method02
     */
    void method02();
}

适配器Adapter:

public class Adapter extends Source implements TargetAble{
    /**
     * method01在继承Source中已经实现了,现在只要实现method02就行
     */
    @Override
    public void method02() {
        System.out.println("method02");
    }
}

测试:这样目标接口里就有了Source的功能。

image-20220614230830124.png

对象的适配器模式

简介

和类的适配器模式差不多,类的适配器模式是通过继承来将源类的方法适配,而对象的适配器模式就是通过组合的方式,通过调用组合进来的源对象的方法来实现适配。

实现

源类和目标接口都不变之需要修改适配类就可以

@Data
@AllArgsConstructor
public class Adapter implements TargetAble {
    /**
     * 将Source组合进来
     */
    private Source source;
    @Override
    public void method01() {
        source.method01();
    }
    @Override
    public void method02() {
        System.out.println("适配的method02");
    }
}

接口的适配器模式

简介

接口的适配器模式的出现是为了解决当一个接口的抽象方法过多,而存在实现类不需要却必须要实现的方法。这里使用一个中间的抽象类来实现接口中的所有方法,接下来的实现类不再和接口打交道而是和抽象类打交道,重写各自需要的方法即可。

实现

创建接口:

public interface ISource {
    /**
     * 方法一,Adapter1需要 而 Adapter2不需要
     */
    void method01();
    
    /**
     * 方法二,Adapter2需要 而 Adapter1不需要
     */
    void method02();
}

创建抽象类:

public abstract class AbstractClass implements ISource{
    @Override
    public void method01() {
​
    }
    @Override
    public void method02() {
​
    }
}

实现类:

public class Adapter1 extends AbstractClass{
​
    @Override
    public void method01() {
        super.method01();
    }
}
​
public class Adapter2 extends AbstractClass{
​
    @Override
    public void method02() {
        super.method02();
    }
}

这样Adapter1和Adapter2只需要重写对应需要的接口即可,不用完全重写ISource中定义的抽象方法。

其实这就是违反了接口隔离原则,当我们发现一个借口过于庞大或存在可以拆分的可能性的话在开发阶段就应立刻重构。

接口拆分

当下我们有一个接口ISource,存在三个方法Method01、02、03。存在三个实现类,Wrapper1只需要Method01,Wrapper2之需要Method02和Method03,Wrapper3需要三个方法。

ISource:

public interface ISource {
    /**
     * method01 只有Wrapper1需要
     */
    void method01();
    /**
     * method02 
     */
    void method02();
    /**
     * method03
     */
    void method03();
}

拆分成两个接口:ISource1和ISource23:

public interface ISource1 {
    /**
     * method01 只有Wrapper1需要
     */
    void method01();
}
public interface ISource23 {
    /**
     * method02
     */
    void method02();
    /**
     * method03
     */
    void method03();
}

实现类:

Wrapper1和Wrapper2只需要实现对应接口,Wrapper3可以使用实现多个接口的方式

public class Wrapper1 implements ISource1{
    @Override
    public void method01() {
        System.out.println("方法一需要实现的方法");
    }
}
public class Wrapper2 implements ISource23{
    @Override
    public void method02() {
        System.out.println("Wrapper2需要的方法 method02");
    }
​
    @Override
    public void method03() {
        System.out.println("Wrapper2需要的方法 method03");
    }
}
public class Wrapper3 implements ISource23, ISource1{
    @Override
    public void method02() {
    }
    @Override
    public void method03() {
    }
    @Override
    public void method01() {
    }
}

总结

这三种适配模式都有对应的应用场景:

  • 类的适配器模式

    当我们希望一个类转换成满足另一个接口的类时,可以使用类的适配器模式。1⃣️新定义的接口存在和源类方法相同的抽象方法2⃣️定义适配器继承源类实现接口

  • 对象的适配器模式

    当我们希望一个对象转换成满足另一个接口的对象时,可以使用对象的适配器模式。1⃣️新定义的接口存在和源类方法相同的抽象方法2⃣️定义适配器继承源类实现接口2⃣️将源对象组合进来3⃣️调用对象的方法即可

  • 接口的适配器模式

    当一个接口过于庞大且存在实现类不需要重写的抽象方法的时,我们可以使用接口的适配器模式。1⃣️定义抽象类,实现接口中的所有方法 2⃣️定义实现类和抽象类打交道,不可接口打交道,只需要实现需要的方法即可。

    出现这种情况一般违反了单一原则、接口隔离原则,所以可以进行接口拆分,使用接口可以多实现的方式避免这种问题。