关于设计模式:设计模式学习笔记九适配器模式

43次阅读

共计 3970 个字符,预计需要花费 10 分钟才能阅读完成。

1 适配器模式

1.1 定义

将一个接口转换为客户心愿的另一个接口,使接口不兼容的那些类能够一起工作,别名为包装器。
适配器中的接口是狭义的接口,能够示意一个办法或者办法的汇合。

适配器模式既能够作为类结构型模式,也能够作为对象结构型模式。

1.2 分类

依据适配器与适配者类的关系不同,能够分为对象适配器模式以及类适配器模式。

1.2.1 对象适配器模式

对象适配器模式就是适配器与适配者之间是关联关系
结构图如下:

1.2.2 类适配器模式

类适配器模式就是适配器与适配者之间是继承或实现关系。
结构图如下:

因为语言个性的限度,比方 Java,C# 不反对多重继承,类适配器模式受到很多限度,例如 Target 如果不是接口而是一个类,就无奈应用类适配器模式。此外如果适配者为 final 类也无奈应用适配器模式,在 Java 等语言中大部分状况下应用对象适配器模式。

1.3 角色

  • Target(指标抽象类):指标抽象类定义客户所需的接口,能够是一个抽象类或接口,也能够是一个具体类
  • Adapter(适配器类):适配器能够调用另一个接口,作为一个转换器,对 Adaptee 和 Target 进行适配。适配器类是适配器模式的外围,在对象适配器模式中,它通过继承 Target 并关联一个 Adaptee 对象使两者产生分割
  • Adaptee(适配者类):适配者即被适配的角色,它定义了一个曾经存在的接口,这个接口须要适配,适配者类个别是一个具体类,蕴含了客户心愿应用的业务办法,在某些状况下可能没有适配者类的源代码

2 实例

2.1 对象适配器

Target 类以及实现了 Target 的类:

interface Target
{void request();
}

class ConcreteTarget implements Target
{
    @Override
    public void request()
    {System.out.println("具体 Target 办法");
    }
}

适配者类:

class Adaptee
{public void specificRequest()
    {System.out.println("Adaptee 办法");
    }
}

适配器类(实现了 Target,适配者作为成员变量):

class Adapter implements Target
{private Adaptee adaptee = new Adaptee();
    @Override
    public void request()
    {adaptee.specificRequest();
    }
}

测试:

public class Test
{public static void main(String[] args) 
    {Target target = new ConcreteTarget();
        target.request();
        Target adapter = new Adapter();
        adapter.request();}
}

2.2 类适配器

在上述对象适配器的根底上,适配者与 Target 放弃不变,适配器继承了适配者并实现了 Target,同时勾销了适配者作为成员变量,在办法内间接调用super.xxx,也就是适配者的办法:

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

2.3 Micro USB 与 Type-C

假如目前只有一条 Micro USB 线以及一台只有 Type- C 接口的手机,须要对其进行充电,这时候就须要一个转接头把 Micro USB 转为 Type- C 接口,能力给手机充电。
这里的 Target 就是 Type-C,适配者就是 Micro USB,适配器就是转接头,简化实现代码如下:

public class Test
{public static void main(String[] args) {TypeC typeC = new MicroUSBToTypeC();
        typeC.chargeWithTypeC();}
}

//Target: 给 TypeC 接口的手机充电
interface TypeC
{void chargeWithTypeC();
}

//Adaptee: 适配者,MicroUSB 线
class MicroUSB
{public void chargeWithMicroUSB()
    {System.out.println("MicroUSB 充电");
    }
}

//Adapter: 适配器,MicroUSB 到 TypeC 的转接头
class MicroUSBToTypeC implements TypeC
{private MicroUSB microUSB = new MicroUSB();
    @Override
    public void chargeWithTypeC()
    {microUSB.chargeWithMicroUSB();
    }
}

3 双向适配器

在对象适配器的应用过程中,如果在适配器中同时蕴含对 Target 类和 Adaptee 类的援用,Adaptee 类能够通过适配器调用 Target 类中的办法,Target 类也能够通过适配器调用 Adaptee 类的办法,那么该适配器就是一个双向适配器。例子如下:

public class Test
{public static void main(String[] args) {Adapter adapter = new Adapter();
        adapter.request();
        adapter.specificRequest();}
}

// 适配者
interface Adaptee
{void specificRequest();
}

//Target 类
interface Target
{void request();
}

//Target 实现
class TargetImpl implements Target
{
    @Override
    public void request()
    {System.out.println("Target 办法");
    }
}

// 适配者实现
class AdapteeImpl implements Adaptee
{
    @Override
    public void specificRequest()
    {System.out.println("Adaptee 办法");
    }
}

// 适配器
class Adapter implements Adaptee,Target
{private Target target = new TargetImpl();
    private Adaptee adaptee = new AdapteeImpl();
    @Override
    public void request()
    {
        //Target 的办法调用适配者办法
        adaptee.specificRequest();}

    @Override
    public void specificRequest()
    {
        // 适配者办法调用 Target 的办法
        target.request();}
}

4 缺省适配器

4.1 定义

缺省适配器:当不须要实现一个接口所提供的所有办法时,可先设计一个抽象类实现该接口,并为接口中的每个办法都提供一个默认实现(空实现),那么该抽象类子类能够选择性笼罩父类的某些办法来实现需求,它实用于不想应用一个接口中所有办法的状况,又叫单接口适配器模式。

4.2 结构图

4.3 角色

  • ServiceInterface(适配者接口):通常是一个申明了大量办法的接口
  • AbstractServiceClass(缺省适配器类):缺省适配器模式的外围类,应用空办法的模式实现了在 ServiceInterface 接口中申明的办法,通常定义为抽象类
  • ConcreteServiceClass(具体业务类):是缺省适配器类的子类,只须要有选择性地笼罩适配器者中定义的办法,其余的办法在缺省适配器类中提供了空实现

4.4 实例

Java AWT 中个别能够通过两种形式来解决窗口事件:

  • 实现WindowListener
  • 继承WindowAdapter

其中 WindowAdapter 实现了 WindowListener 接口,然而都是提供了空实现,也就是说实现 WindowsListener 的话须要实现外面所有的办法,而继承 WindowAdapter 只须要选择性地笼罩办法即可,结构图:

5 次要长处

类适配器以及对象适配器的独特长处如下:

  • 解耦:将 Target 与 Adaptee 解耦,引入适配器来重用现有的适配者类,毋庸批改原有构造
  • 进步复用性:将具体的业务实现过程封装在适配者类中,对于客户端而言是通明的,而且进步了适配者类的复用性,同一个适配者类能够在多个不同的零碎复用
  • 扩展性好:能够很不便地更换适配器,也能够在不批改代码的根底上减少了新的适配器类,完全符合开闭准则,扩大灵便

类适配器的独有长处如下:

  • 因为适配器类是适配者的子类,因而在适配器类中置换一些适配者的办法,使得适配器的灵活性更强。

对象适配器的独有长处如下:

  • 一个对象适配器能够把多个不同的适配者适配到同一个 Target
  • 能够适配一个适配者的子类,因为适配器与适配者之间是关联关系,依据 LSP(里氏代换准则),适配者的子类也能够通过该适配器进行适配

6 次要毛病

类适配器毛病:

  • 对于 Java,C# 等不反对多重继承的语言,一次最多只能适配一个适配者类
  • 适配者不能是“不能继承的类”,比方 Java 的 final 类,C# 的 sealed
  • 在 Java,C# 等 Target 只能是接口不能是类

对象适配器毛病:

  • 置换麻烦:相比起类适配器,在适配器中置换适配者的某些办法比拟麻烦,须要先创立一个适配者类的子类,在子类将适配者类的办法置换掉,再把适配者的子类作为真正的适配者类进行适配,实现较为简单

7 实用场景

  • 零碎须要应用一些现有的类,而这些类的接口(如办法名)不合乎零碎的需要,甚至没有这些类的源代码
  • 想创立一个能够重复使用的类,用于与彼此之间没有太大关联的类,包含可能在未来引进的类一起工作

8 总结

正文完
 0