Java Adapter 适配器模式(类适配器,对象适配器)优缺点对比

2020-02-14 19:36栏目:龙竞技官网
TAG:

生活中的一些例子

在我们的日常生活中,对于适配器,可以说是无处不在。例如我们平时使用的笔记本电脑,可能笔记本电脑的工作电压是20V,但我们一般的家庭用电是220V,这时候电脑在充电的时候就需要一个电源适配器来把220V的电脑转化为20V的电压了。这个电源适配器也别称为充电器或变压器。

图片 1image

又如,我们想用苹果的充电线给安卓的手机充电时。由于两者的接口不一样,会导致充电口无法匹配。这时,我们就需要适配器,将安卓的充电接口转化为苹果的接口,这样,就可以进行充电了。

图片 2image

上面说的两个例子,就是今天我们要讲的适配器模式

Java 适配器模式

图片 3adapter阅读原文请访问我的博客BrightLoong's Blog

适配器模定义

适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。

在适配器模式中,存在两种不同的模式结构:类的适配器模式和对象的适配器模式

           最近学习java 基础知识,学习适配器的时候疑惑很多,上网查下资料,对于 Adapter的资料很多,但是比较下本篇不错,这里记录下,大家需要的可以看下。

一. 概述

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

关于适配器,现实生活中也有很多例子,比如电源适配器,中国家庭供电为220V,而手机一般需求是在5V,这里220V就是不兼容的那个类,但我们又需要其供电,我们用电源适配器将其转为5V,使手机能正常充电。还有各种转接头(HDMI转接头,type-c转接头等),顺便说一下,Java中的IO中可以看到适配器模式的使用。

适配器模式属于结构型模式

对象的适配器模式

我们以上面的苹果充电线给安卓手机充电的为例,如果是你来写代码,把他们进行兼容适配,你会怎么写呢?

对于这个问题,我们首先先来看一下适配器模式中涉及到的三个角色:

1、Target:目标抽象类定义客户所需接口,可以是一个抽象类或接口,也可以是具体类。例如对于上面的第二个例子,客户端的目标是要给只接受安卓充电口的安卓手机充电,所以我们的目标抽象类就是安卓充电线的接口

2、Adaptee:适配者即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类一般是一个具体类,包含了客户希望使用的业务方法。例如上面苹果充电线就是适配者类

3、Adapter:通过包装一个需要适配的对象,把原接口转换成目标接口。例如为了可以充电,我们需要一个适配器,使之一边可以连接安卓充电的接口,一边可以连接苹果充电线的接口。

UML图

图片 4image

下面我们用代码来做个实例:

.Target类

public class Android { public void isAndroid(){ System.out.println("这是一个只接受安卓充电线的插口"); }}

.Adaptee类

public class Iphone { public void isIphone(){ System.out.println("这是一个适配苹果充电线的插口"); }}

.Adapter类:把他们进行适配

/** * 适配器,作为中间件,把他们进行适配 */public class Adapter extends Android{ private Iphone iphone; public Adapter(Iphone iphone){ this.iphone = iphone; } @Override public void isAndroid() { iphone.isIphone(); }}

.测试类

public class Demo { public static void main(String[] args){ Android android = new Adapter(new Iphone; //调用的是安卓的接口,但实际上 //确实一个可以接受苹果充电器的接口 android.isAndroid(); }}

.打印结果

这是一个适配苹果充电线的插口

我们通过适配器的作用,就可以让苹果充电线给安卓手机充电了。。

对于这种对象的适配器模式,实际上就是通过一个适配器类,把目标类和需要被适配的类进行组合。所以适配器类Adapter一般需要继承或实现Targert,并且还得持有Adaptee的实例引用。

适配器模式就是把一个类的接口转换成客户端所期待的另外一种接口,从而使原接口不匹配而无法在一起工作的的两个类能在一起工作。从功能上说,这些接口不兼容的类一般具有相同或相似的功能。通常我们通过修改该类的接口来解决这种接口不兼容的情形,但是如果我们不愿意为了一个应用而修改各原接口,或者我们压根儿就没有对象的源代码的时候,适配器模式就会派上用场了。

二. UML类图解析

在GoF的设计模式中,适配器模式讲了两种类型——类适配器模式和对象适配器模式。由于类适配器模式需要继承被适配的类,同时有可能需要继承目标类,而Java又不支持多重继承,所以平时常用的是对象适配器模式。下面也会对类适配器模式进行简单的介绍。

图片 5adapter

  • Client:客户端。
  • Target:目标接口,客户端所期待的目标接口(可以是具体的或抽象的类,也可以是接口)。
  • Adapter:适配器,实现目标接口,通过在内部持有一个Adaptee引用,把源接口转成目标接口。
  • Adaptee:需要适配的类。

图片 6adapter

基本和对象适配器模式相同,唯一不同的是适配器不在持有Adaptee的引用,而采用继承Adaptee的方式,实现把源接口转成目标接口。

类的适配器模式

除了对象的适配器模式,还有另外一种类的适配器模式。在这种模式中,Adapter不持有Adaptee的实例引用,而是直接继承Adaptee类,然后再实现Target接口。或者直接继承Adaptee类和Target类,但由于Java中不支持多重继承,所以只能用实现Target的方式。

这也导致了在Jaca类的适配器模式中,Target必须是一个接口而不可以是抽象类和具体类(因为Java不支持多重继承)。

把上面那个例子改写一下,用类的适配器模式来实现:

.Target接口类

interface Android { void isAndroid();}

.Adaptee类

public class Iphone { public void isIphone(){ System.out.println("这是一个适配苹果充电线的接口"); }}

.Adapter类:继承Adaptee,实现Target

/** * 适配器,把安卓手机的插口转化为可以用苹果充电线充电的接口 */public class Adapter extends Iphone implements Android{ @Override public void isAndroid() { //直接调用 isIphone(); }}

.测试类

public class Demo { public static void main(String[] args){ Android android = new Adapter(); android.isAndroid(); }}

.打印结果

这是一个适配苹果充电线的接口

对于这种类的适配器模式,在Java中是使用的比较少的。

这两种方式最重要的区别就是:

对象适配器模式通过组合来实现适配器功能,而类的适配器模式通过多继承或实现来实现适配器功能

适配器的优点:

三. 代码实现

就基于上面的电源适配器场景来进行代码实现。目标接口——MobileCharge,需要被适配的22V电源——Power220V,电源适配器——PowerAdapter

package io.github.brightloong.design.adapter;/** * 充电接口 * Created by BrightLoong on 2018/6/6. */public interface MobileCharge { public void outPut5V();}

package io.github.brightloong.design.adapter;/** * 需要被适配的类 * Created by BrightLoong on 2018/6/6. */public class Power220V { public void outPut220V() { System.out.println("输出220V电流"); }}

package io.github.brightloong.design.adapter;/** * 对象适配器 * Created by BrightLoong on 2018/6/6. */public class PowerAdapter implements MobileCharge { //需要适配的220V电源 private Power220V power220V; public PowerAdapter(Power220V power220V) { this.power220V = power220V; } public void outPut5V() { power220V.outPut220V(); System.out.println("电源适配器转换"); System.out.println; }}

package io.github.brightloong.design.adapter;/** * 类适配器,使用继承的方式 * Created by BrightLoong on 2018/6/6. */public class PowerAdapter2 extends Power220V implements MobileCharge { public void outPut5V() { super.outPut220V(); System.out.println("电源适配器转换"); System.out.println; }}

package io.github.brightloong.design.adapter;/** * Created by BrightLoong on 2018/6/6. */public class Client { public static void main(String[] args) { MobileCharge mobileCharge = new PowerAdapter(new Power220V; System.out.println; mobileCharge.outPut5V(); System.out.println("-------------------"); //类适配器模式 MobileCharge mobileCharge2 = new PowerAdapter2(); mobileCharge2.outPut5V(); }}

输出结果:

手机充电输出220V电流电源适配器转换输出5V电流-------------------输出220V电流电源适配器转换输出5V电流

适配器模式的一些优缺点

感觉,优缺点没什么好说的,只有实际上去用过才能体会。反正最重要的优点就是将不兼容的几个接口通过一个中间类,把他们进行适配,并且这个适配的过程对于客户端来说是透明的,客户端并不知道发生了啥,只知道它通过一个适配器,就可以获取到目标接口了。

至于缺点嘛,如果动不动就使用适配器,那么我觉得会使整个类系统变的有点零散,并且以后要重构了会更加复杂......

关注公我的众号:苦逼的码农,获取更多原创文章,后台回复礼包送你一份时下热门的资源大礼包。同时也感谢把文章介绍给更多需要的人

1、将目标类和适配者类解耦

四. 总结

注意:适配器模式是更多的为了解决已有的在运行的项目中的问题,而不是解决开发阶段的项目,开发阶段的项目应该进行良好的设计。

  • 系统的数据和行为都正确,但接口不符时。
  • 希望复用一些现存的类,但是接口又与复用环境要求不一致的情况。
  • 想使用一个已经存在的类,但是它的接口,也就是它的方法和你的要求不同时。
  • 因为适配器模式可以让不满足要求的类满足要求,所以提高了类的复用。
  • 使目标类和适配者类解耦,增加了类的透明性,通过引入一个适配器类来重用现有的适配者类,无需修改原有结构。
  • 具有较强的灵活性和扩展性,可以很方便的增加适配器。
  • 一次最多只能适配一个适配者类,不能同时适配多个适配者。 (类适配器存在的问题,因为不能多重继承,考虑使用对象适配器,持有多个适配者)
  • 目标抽象类只能为接口,不能为类,其使用有一定的局限性。(类适配器存在的问题,因为不能多重继承,如果是类,考虑继承而不是实现)
  • 对象适配器

2、增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性

3、灵活性和扩展性都非常好,符合开闭原则

适配器所涉及的角色包括下面几种:

目标(Target):定义一个客户端使用的特定接口。

客户端(Client):使用目标接口,与和目标接口一致的对象合作。

被适配者(Adaptee):一个现存需要适配的接口。

适配器(Adapter):负责将Adaptee的接口转换为Target的接口。适配器是一个具体的类,这是该模式的核心。

适配器分为类适配器和对象适配器两种,下面将详细讲述。

类适配器

版权声明:本文由龙竞技官网发布于龙竞技官网,转载请注明出处:Java Adapter 适配器模式(类适配器,对象适配器)优缺点对比