设计模式-适配器模式

二次信任 提交于 2019-11-30 15:06:51

介绍

结构型模式是将系统中的多个类或对象组合在一起,相互协作来完成更复杂的任务或功能。就好比搭积木,许多简单积木可以搭建成更复杂、功能更强大的结构。它分为两种形式:类结构型模式和对象结构型模式。类结构型模式由多个类组合,存在继承和实现关系;对象结构型模式由类和对象组合,存在关联关系(比如车和轮胎的关系)。

意图:

将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

主要解决:

主要解决在软件系统中,常常要将一些"现存的对象"放到新的环境中,而新环境要求的接口是现对象不能满足的。

何时使用:

  1. 系统需要使用现有的类,而此类的接口不符合系统的需要。
  2. 想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有一致的接口。
  3. 通过接口转换,将一个类插入另一个类系中。(比如老虎和飞禽,现在多了一个飞虎,在不增加实体的需求下,增加一个适配器,在里面包容一个虎对象,实现飞的接口。)

如何解决:

继承或依赖(推荐)。

关键代码:

适配器继承或依赖已有的对象,实现想要的目标接口。

应用实例:

  1. 美国电器 110V,中国 220V,就要有一个适配器将 110V 转化为 220V。
  2. JAVA JDK 1.1 提供了 Enumeration 接口,而在 1.2 中提供了 Iterator 接口,想要使用 1.2 的 JDK,则要将以前系统的 Enumeration 接口转化为 Iterator 接口,这时就需要适配器模式。
  3. 在 LINUX 上运行 WINDOWS 程序。
  4. JAVA 中的 jdbc。

优点:

  1. 可以让任何两个没有关联的类一起运行。
  2. 提高了类的复用。
  3. 增加了类的透明度。
  4. 灵活性好。

缺点:

  1. 过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。
  2. 由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。使用场景:有动机地修改一个正常运行的系统的接口,这时应该考虑使用适配器模式。注意事项:适配器不是在详细设计时添加的,而是解决正在服役的项目的问题。

实例

  1. 模式结构:
  • Target(目标抽象类):定义了特定的工作接口。
  • Adapter(适配器类):模式的核心类,作为转换器对Target和Adaptee进行适配。
  • Adaptee(适配者类):定义了需要适配的接口。
  • Client(客户类):针对目标抽象类编程,调用其定义的方法。
  1. 类适配器和对象适配器的比较:

类适配器中
在这里插入图片描述

适配器类通过实现Target接口并继承Adaptee类,实现适配目的。

public class Adapter extends Adaptee implements Target
{    
    //request()方法为Target接口里所定义的方法
    public void request()
    {   
        //该方法为Adaptee类里定义的方法
        specificRequest();
    }
}

对象适配器中
在这里插入图片描述

适配器类通过继承Target类(也可以实现Target接口)并关联一个Adaptee对象,实现适配目的。

public class Adapter extends Target
{
   //所关联的适配者类的对象
    private Adaptee adaptee;
    public Adapter(Adaptee adaptee)
    {
        this.adaptee=adaptee;
    }
    public void request()
    {
        adaptee.specificRequest();
    }
}

适配器的权衡

  1. 类适配器使用对象继承的方式,是静态的定义方式;而对象适配器使用对象组合的方式,是动态组合的方式。
  2. 对于类适配器,由于适配器直接继承了Adaptee,使得适配器不能和Adaptee的子类一起工作,因为继承是静态的关系,当适配器继承了Adaptee后,就不可能再去处理 Adaptee的子类了。    
    对于对象适配器,一个适配器可以把多种不同的源适配到同一个目标。换言之,同一个适配器可以把源类和它的子类都适配到目标接口。因为对象适配器采用的是对象组合的关系,只要对象类型正确,是不是子类都无所谓。
  3. 对于类适配器,适配器可以重定义Adaptee的部分行为,相当于子类覆盖父类的部分实现方法。    
    对于对象适配器,要重定义Adaptee的行为比较困难,这种情况下,需要定义Adaptee的子类来实现重定义,然后让适配器组合子类。虽然重定义Adaptee的行为比较困难,但是想要增加一些新的行为则方便的很,而且新增加的行为可同时适用于所有的源。  
    4.对于类适配器,仅仅引入了一个对象,并不需要额外的引用来间接得到Adaptee。    
    对于对象适配器,需要额外的引用来间接得到Adaptee。

建议尽量使用对象适配器的实现方式,多用合成/聚合、少用继承。当然,具体问题具体分析,根据需要来选用实现方式,最适合的才是最好的。

缺省适配模式的结构

缺省适配模式是一种“平庸”化的适配器模式
在这里插入图片描述

public interface AbstractService {
    public void serviceOperation1();
    public int serviceOperation2();
    public String serviceOperation3();
}
public class ServiceAdapter implements AbstractService{

    @Override
    public void serviceOperation1() {
    }

    @Override
    public int serviceOperation2() {
        return 0;
    }

    @Override
    public String serviceOperation3() {
        return null;
    }

}

可以看到,接口AbstractService要求定义三个方法,分别是serviceOperation1()、serviceOperation2()、serviceOperation3();而抽象适配器类ServiceAdapter则为这三种方法都提供了平庸的实现。因此,任何继承自抽象类ServiceAdapter的具体类都可以选择它所需要的方法实现,而不必理会其他的不需要的方法。

适配器模式的用意是要改变源的接口,以便于目标接口相容。缺省适配的用意稍有不同,它是为了方便建立一个不平庸的适配器类而提供的一种平庸实现。  
在任何时候,如果不准备实现一个接口的所有方法时,就可以使用“缺省适配模式”制造一个抽象类,给出所有方法的平庸的具体实现。这样,从这个抽象类再继承下去的子类就不必实现所有的方法了。

参考文档
https://www.cnblogs.com/winkey4986/p/5482064.html
https://segmentfault.com/a/1190000011856448

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!