适配器模式

Posted 蜜蜂采蜜

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了适配器模式相关的知识,希望对你有一定的参考价值。

网址链接1:https://segmentfault.com/a/1190000011856448

网址链接2:https://www.cnblogs.com/lwbqqyumidi/p/3750128.html

适配器就是一种适配中间件,它存在于不匹配的二者之间,用于连接二者,将不匹配变得匹配,简单点理解就是平常所见的转接头,转换器之类的存在。

  适配器模式有两种:类适配器、对象适配器、接口适配器

  前二者在实现上有些许区别,作用一样,第三个接口适配器差别较大。

1、类适配器模式:

  原理:通过继承来实现适配器功能。

  当我们要访问的接口A中没有我们想要的方法 ,却在另一个接口B中发现了合适的方法,我们又不能改变访问接口A,在这种情况下,我们可以定义一个适配器p来进行中转,这个适配器p要实现我们访问的接口A,这样我们就能继续访问当前接口A中的方法(虽然它目前不是我们的菜),然后再继承接口B的实现类BB,这样我们可以在适配器P中访问接口B的方法了,这时我们在适配器P中的接口A方法中直接引用BB中的合适方法,这样就完成了一个简单的类适配器。

本文结合自己的理解,阐述下对适配器模式的看法。

假设系统存在一个现有的类UserInfo:

 public class UserInfo 
     private Map<String, String> userBaseInfo;
     public Map getUserBaseInfo() 
         return userBaseInfo;
     
     public void setUserBaseInfo(Map<String, String> userBaseInfo) 
         this.userBaseInfo = userBaseInfo;
     
 

客户端可以通过如下方式set、get员工基本信息:

public class AdapterTest 
     public static void main(String[] args) 
        
         UserInfo oui = new UserInfo();
         Map<String, String> inUserInfo = new HashMap<String, String>() 
             
                 put("name", "corn");
                 put("telNumber", "170xxxxxxxx");
             
         ;
          oui.setUserBaseInfo(inUserInfo);
         // 原有取得员工基本信息的方式
         Map<String, String> outUserInfo = oui.getUserBaseInfo();
         String name = outUserInfo.get("name");
         String telNumber = outUserInfo.get("telNumber");
        
     
 

有一天,基于某种原因(也许你看着这种取数据的方式不太爽,也许是系统间数据交换的原因等),你需要按照如下接口的方式取数据:

目标员工接口:

interface UserInterface 
     public String getName();
     public String getTelNumber();
 

那么,现在的问题是,如何将一个既定的类转换成按照目标接口的所期望的行为形式呢?

具体怎样实现呢,可以通过如下方式进行:

 class UserAdapter extends UserInfo implements UserInterface 
     @Override
     public String getName() 
         return (String) super.getUserBaseInfo().get("name");
     
     @Override
     public String getTelNumber() 
         return (String) super.getUserBaseInfo().get("telNumber");
     
 

从上面的UserAdapter类定义中我们发现,UserAdapter不仅实现了UserInterface接口,同时还继承了UserInfo类。在实现接口的getName()和getTelNumber()方法中,分别调用了UserInfo类中的相应方法并取得结果。由此可以满足需求。在上述定义中,按照UserInterface、UserInfo和UserAdapter在场景中的目的不同,可以具体划分成如下角色:

UserInterface:目标角色——目标接口,系统所期待实现的目标;

UserInfo:源角色——当前已经存在的原有的实现类,即将被适配的类;

UserAdapter:适配器角色——将原有实现装换为目标接口的实现。

简单点说,适配器模式是指:定义一个类,将一个已经存在的类,转换成目标接口所期望的行为形式。

在具体的实现过程中,又可以基于其实现层次是类层次还是对象层次,将其分为类适配器和对象适配器。如上所写的是类适配器。

2、对象适配器

对象适配器使用组合代替继承,将源角色视为适配器角色的属性:

class UserAdapter implements UserInterface 
    
    private UserInfo userInfo;
    
     public UserAdapter()
        
     
    
     public UserAdapter(UserInfo userInfo)
         this.userInfo = userInfo;
     
     @Override
     public String getName() 
         return (String) userInfo.getUserBaseInfo().get("name");
     
     @Override
     public String getTelNumber() 
         return (String) userInfo.getUserBaseInfo().get("telNumber");
     
 

总体而言:适配器模式是指定义一个适配器类,将一个已经存在的类,转换成目标接口所期望的行为形式。同时,一般来说,基于更多的推荐使用组合而不是继承,因此,对象适配器可能使用更多。

3、JDK 中的适配器使用

使用适配器模式的类

java.util.Arrays#asList()

java.io.InputStreamReader(InputStream)

java.io.OutputStreamWriter(OutputStream)

 

Java I/O 库大量使用了适配器模式,如 ByteArrayInputStream 是一个适配器类,它继承了 InputStream 的接口,并且封装了一个 byte 数组。换言之,它将一个 byte 数组的接口适配成 InputStream 流处理器的接口。

在 OutputStream 类型中,所有的原始流处理器都是适配器类。ByteArrayOutputStream 继承了 OutputStream 类型,同时持有一个对 byte 数组的引用。它一个 byte 数组的接口适配成 OutputString 类型的接口,因此也是一个对象形式的适配器模式的应用。

FileOutputStream 继承了 OutputStream 类型,同时持有一个对 FileDiscriptor 对象的引用。这是一个将 FileDiscriptor 接口适配成 OutputStream 接口形式的对象型适配器模式。

Reader 类型的原始流处理器都是适配器模式的应用。StringReader 是一个适配器类,StringReader 类继承了 Reader 类型,持有一个对 String 对象的引用。它将 String 的接口适配成 Reader 类型的接口。 

4、接口适配器模式

  原理:通过抽象类来实现适配,这种适配稍别于上面所述的适配。

  当存在这样一个接口,其中定义了N多的方法,而我们现在却只想使用其中的一个到几个方法,如果我们直接实现接口,那么我们要对所有的方法进行实现,哪怕我们仅仅是对不需要的方法进行置空(只写一对大括号,不做具体方法实现)也会导致这个类变得臃肿,调用也不方便,这时我们可以使用一个抽象类作为中间件,即适配器,用这个抽象类实现接口,而在抽象类中所有的方法都进行置空,那么我们在创建抽象类的继承类,而且重写我们需要使用的那几个方法即可。

5、适配器模式应用场景

类适配器与对象适配器的使用场景一致,仅仅是实现手段稍有区别,二者主要用于如下场景:

  (1)想要使用一个已经存在的类,但是它却不符合现有的接口规范,导致无法直接去访问,这时创建一个适配器就能间接去访问这个类中的方法。

  (2)我们有一个类,想将其设计为可重用的类(可被多处访问),我们可以创建适配器来将这个类来适配其他没有提供合适接口的类。

  以上两个场景其实就是从两个角度来描述一类问题,那就是要访问的方法不在合适的接口里,一个从接口出发(被访问),一个从访问出发(主动访问)。

6、接口适配器使用场景

  (1)想要使用接口中的某个或某些方法,但是接口中有太多方法,我们要使用时必须实现接口并实现其中的所有方法,可以使用抽象类来实现接口,并不对方法进行实现(仅置空),然后我们再继承这个抽象类来通过重写想用的方法的方式来实现。这个抽象类就是适配器。

以上是关于适配器模式的主要内容,如果未能解决你的问题,请参考以下文章

适配器模式(Adapter)

GShang博客园主题高级版本适配教程详解

源码分析之委派模式与适配器模式

7.适配器模式

关于适配器模式的 个人理解

Java单体应用 - 架构模式 - 03.设计模式-06.适配器模式