适配器模式

87 阅读4分钟

Adapter.

别名:包装器 Wrapper


定义

将一个类的接口转换成所希望的另外一个接口。使由于接口不兼容的对象能够相互合作


应用场景

1.希望使用某个类。但该接口与其他代码不兼容时,可以使用适配器类

适配器模式允许你创建一个中间层类,其可作为代码与遗留类、第三方类或提供怪异接口的类之间的转换器

2.需要复用 处于同一个继承体系,并且他们又有额外的一些共同的方法,但是这些共同的方法不是所有在这一继承体系中的子类所具有的共性

可以扩展每个子类,将缺少的功能添加到新的子类中。但是,必须在所有新子类中重复添加这些代码,这样会埋下隐患。


实现方法

1.确保至少有两个类的接口不兼容:

一个无法修改(通常是第三方、遗留系统或者存在众多已有依赖的类)的功能性服务类

一个或多个将受益于使用服务类的客户端

2.声明客户端接口,描述客户端如何与服务交互

3.创建遵循客户端接口的适配器类。所有方法暂时为空

4.在适配器类中添加一个成员变量用于保存对于服务对象的引 用。 通常情况下会通过构造函数对该成员变量进行初始化, 但有时在调用其方法时将该变量传递给适配器会更方便。

5.依次实现适配器类客户端接口的所有方法。 适配器会将实际 工作委派给服务对象, 自身只负责接口或数据格式的转换。

6.客户端必须通过客户端接口使用适配器。 这样一来, 你就可 以在不影响客户端代码的情况下修改或扩展适配器。


优缺点

优点

1.单一职责原则,你可以将接口或数据转换代码从程序主要业务逻辑中分离。

2.开闭原则。只要客户端代码通过客户端接口与适配器进行交互,你就能不修改现有客户端代码的情况下在程序中添加新类型的适配器

缺点:

1.代码整体复杂度增加,因为需要新增一系列接口和类。有时直接更改服务类使其与其他代码兼容会更简单。


结构

对象适配器

采用构成原则:适配器实现其中一个对象的接口,并对另外一个对象进行封装

classDiagram
Client-->Client Interface
Adapter..|>Client Interface
Adapter-->Service
class Client Interface{
	<<interface>>
	+method(data)
}
class Adapter{
	-adaptee:Service
	+method(data)
}
class Service{
	...
	+serviceMethod(specialData)
}

类适配器

采用继承机制:适配器同时继承两个对象的接口

classDiagram
Client-->Existing Class
Adapter--|>Existing Class
Adapter--|>Service
class Existing Class{
	...
	+method(data)
}
class Adapter{
	...
	+method(data)
}
class Service{
	...
	+serviceMethod(specialData)
}

参与者

1.客户端 ( Client ) :是包含当前程序业务逻辑的类

2.客户端接口 ( Client Interface ) :描述了其他类与客户端代码合作时必须遵循的协议。

3.服务( Service ) :有一些功能类。客户端与其接口不兼容,因此无法直接调用

4.适配器 ( Adapter ) :可以同时与客户端和服务交互的类。


适配器解决手机充电问题

想给手机充电,家用电的220V交流电则需要转换成适配司机的5V,则充电器充当了适配器。

 

对象适配器模式

相对于类适配器而言,适配器不再是继承 被适配类,而是持有被适配类。即 持有 被适配类,实现 适配功能接口。

classDiagram
Client ..>Phone
Phone..>Voltage5VInterface
Voltage5V..|>Voltage5VInterface
Voltage220V --o Voltage5V

代码

需要修改的类:适配类

//适配器
public class VoltageAdapter implements Voltage5V {
   private Voltafe220V voltafe220V;
​
   public VoltageAdapter(Voltafe220V voltafe220V){
       this.voltafe220V = voltafe220V;
  }
​
   @Override
   public int output5V() {
       int dst = 0;
​
       if (null != voltafe220V){
           int src = voltafe220V.output220V();
           dst = src/44;
           System.out.println("适配成功,输出 "+dst+"V");
​
      }
​
       return dst;
  }
}
public class Client {
   public static void main(String[] args) {
       Phone p = new Phone();
       p.charging(new VoltageAdapter(new Voltafe220V()));
  }
}

类适配器

classDiagram
Client ..>Phone
Phone..>Voltage5VInterface
VoltageAdapter..|>Voltage5VInterface
VoltageAdapter ..|>V Voltage220V

代码

//被适配类
public class Voltafe220V {
   public int output220V(){
       int src =220;
       System.out.println("电压为 "+src+"V");
       return src;
  }
}
​
//适配接口
public interface Voltage5V {
   public int output5V();
}
//适配器,简单的理解:我有220V 但要实现5V功能接口
public class VoltageAdapter extends Voltafe220V implements Voltage5V {
   @Override
   public int output5V() {
       int src = output220V();
       int dst = src/44//转换成5V
       return dst;
  }
}
public class Phone {
   //充电功能
   public void charging(Voltage5V voltage5V){
       if (voltage5V.output5V() == 5){
           System.out.println("电压为5V,进行充电");
      }else {
           System.out.println("电压不为5V,不能充电");
      }
  }
}
public class Client {
   public static void main(String[] args) {
       Phone p = new Phone();
       p.charging(new VoltageAdapter());
  }
}

注意细节:

1.Java是单继承机制,所以类适配器要继承 被适配类 算是一个缺点,且要求 实现功能是接口,具有一定的局限性。 2.被适配类的相关方法会被适配器实现,使其需要重写,增加了灵活性。但也增加了使用成本。