应用场景

使用者依赖的接口与提供者的接口不匹配时,就加一层适配,而不修改两端的代码

生活中使用的风扇,假设插头是两孔的,但是我们家里墙上的插座只有三孔的,这个时候就需要一个适配器了,这个适配器就是外面买的插座,以上场景为例,写一个例子:

三孔的插座:

public class ThreeOutlet {
/** 三孔插座 */
public void link(String positive, String negative, String earthWire) {
System.out.println(String.format("多一根地线,保证安全用电:%s %s %s", positive, negative, earthWire));
}
}

我们使用电风扇需要启动和关闭的接口:

public interface TwoOutlet {
/** 启动 */
void power(String positive, String negative); /** 关闭 */
void shutDown();
}

适配插座,外面买来的,可以使用两孔的、三孔的:

public class Adapter1 extends ThreeOutlet implements TwoOutlet {

    private String ew = "多一根地线";	// 私有内置地线

    @Override
public void power(String positive, String negative) {
link(positive, negative, ew);
} @Override
public void shutDown() {
System.out.println("拔掉插头");
} @Override
public void link(String positive, String negative, String earthWire) {
super.link(positive, negative, earthWire);
}
}

电风扇类:

public class Fanner {

    private TwoOutlet outlet;

    public void run() {
outlet.power("1", "0");
System.out.println("获得动力");
System.out.println("风扇运转");
outlet.shutDown();
System.out.println("关闭电力,风扇停止运转");
} public void setOutlet(TwoOutlet outlet) {
this.outlet = outlet;
}
}

测试类:

public class Test {

    public static void main(String[] args) {
Fanner fanner = new Fanner();
Adapter1 adapter1 = new Adapter1();
fanner.setOutlet(adapter1);
fanner.run();
}
}



类图:

适配器模式

定义

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

意图

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

主要解决问题

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

何时使用

  1. 系统需要使用现有的类,而此类的接口不符合系统的需要
  2. 想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有一致的接口
  3. 通过接口转换,将一个类插入另一个类系中

优缺点

优点:

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

缺点:

  1. 过多地使用适配器,会让系统非常零乱,不易整体进行把握
  2. 由于JAVA至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类

类图:



涉及到的角色:

  1. 目标(Target)角色:这就是所期待的接口,目标可以是具体的或抽象的类
  2. 源(Adaptee)角色:现有需要适配的接口
  3. 适配器(Adapter)角色:适配器类是本模式的核心;适配器将源接口转换为目标接口;显然,这一角色不能是接口,而必须是具体类

类的适配器模式的结构:

Target接口:

public interface Target {

    /** 源类也有的方法 */
void sampleOperation1(); /** 源类没有的方法 */
void sampleOperation2();
}

Adaptee源角色:

public class Adaptee {

    public void sampleOperation1(){
System.out.println("源类也有的方法");
}
}

Adapter适配器角色:

public class Adapter extends Adaptee implements Target {

    /** 源类和目标类都有的方法 */
@Override
public void sampleOperation1() {
super.sampleOperation1();
} /** 源类没有的方法,期望有这个方法 */
@Override
public void sampleOperation2() { }
}

对象的适配器模式的结构:

Target接口:

public interface Target {

    /** 源类也有的方法 */
void sampleOperation1(); /** 源类没有的方法 */
void sampleOperation2();
}

Adaptee源角色:

public class Adaptee {

    public void sampleOperation1(){
System.out.println("源类也有的方法");
}
}

Adapter适配器角色:

public class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
} /** 源类和目标类都有的方法 */
@Override
public void sampleOperation1() {
this.adaptee.sampleOperation1();
} /** 源类没有的方法,期望有这个方法 */
@Override
public void sampleOperation2() {
System.out.println("适配一个方法");
}
}

需要注意的是,适配器不是在开始设计的时候用的,而是在解决现有的项目中的问题

指鹿为马VS指方为圆

指鹿为马

赵高指鹿为马的故事都应该听说过,下面以适配器模式做个小例子:

现在需要的是一匹马:

public interface NeedHorse {

    /** 需要一匹马 */
void needHorse();
}

但是有的是一只鹿:

public class DeerAdaptee {

    public void deer() {
System.out.println("我是一头鹿,有人要指鹿为马!");
}
}

把鹿适配为马,指鹿为马:

public class DeerChangeAdapter implements NeedHorse {

    private DeerAdaptee deerAdaptee;

    public DeerChangeAdapter(DeerAdaptee deerAdaptee) {
this.deerAdaptee = deerAdaptee;
this.deerAdaptee.deer();
} public void deer() {
System.out.println("我是一头鹿,有人要指鹿为马!");
} @Override
public void needHorse() {
System.out.println("我是一匹马(其实我的真实身份是一只鹿)");
}
}

测试类:

public class Test {

    public static void main(String[] args) {
System.out.println("这个是鹿还是马?");
DeerAdaptee adaptee = new DeerAdaptee();
DeerChangeAdapter adapter = new DeerChangeAdapter(adaptee);
adapter.needHorse();
}
}



类图:

指方为圆

古有指鹿为马,现有指方为圆,nice:

我们需要的是一个球:

public interface BallIF {

    /** 计算体积 */
Double calculateVolume(); /** 计算面积 */
Double calculateAcreage(); /** 半径取值 */
Double getRadius(); /** 半径赋值 */
Double setRadius(double radius);
}

现在有的是一个立方体:

public class Cube {

    private Double width;

    public Cube(Double width) {
this.width = width;
} /** 计算体积 */
public Double calculateVolume() {
return width * width * width;
} /** 计算面积 */
public Double calculateAcreage() {
return width * width;
} /** 长度取值 */
public Double getWidth() {
return width;
} /** 长度赋值 */
public void setWidth(Double width) {
this.width = width;
}
}

适配器适配一下,指方为圆:

public class MagicFinger implements BallIF {

    private double radius = 0;

    private static double PI = 3.14d;

    private Cube adaptee;

    public MagicFinger(Cube adaptee) {
super();
this.adaptee = adaptee;
radius = this.adaptee.getWidth();
} @Override
public Double calculateVolume() {
return (4.0d/3.0d) * PI * (radius * radius);
} @Override
public Double calculateAcreage() {
return PI * 4.0d * (radius * radius * radius);
} @Override
public Double getRadius() {
return radius;
} @Override
public Double setRadius(double radius) {
return this.radius = radius;
}
}

测试一下:

public class Test {
public static void main(String[] args) {
Cube cube = new Cube(2.0);
MagicFinger finger = new MagicFinger(cube);
System.out.println("半径:" + finger.getRadius());
System.out.println("体积:" + finger.calculateVolume());
System.out.println("面积:" + finger.calculateAcreage());
}
}



类图:



如果想有动机地修改一个正常运行的系统的接口,这时应该考虑使用适配器模式

指方画圆之Java设计模式:适配器模式的更多相关文章

  1. Java设计模式——适配器模式

    JAVA 设计模式 适配器模式 用途 适配器模式 (Adapter) 将一个类的接口转换成客户希望的另外一个接口. Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 适配器 ...

  2. 【设计模式】Java设计模式 - 适配器模式

    [设计模式]Java设计模式 - 适配器模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 原创作品,更多关注我CSDN: 一个有梦有戏的人 准备将博客园.CSDN一 ...

  3. JAVA 设计模式 适配器模式

    用途 适配器模式 (Adapter) 将一个类的接口转换成客户希望的另外一个接口. Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 适配器模式是一种结构型模式. 结构

  4. Java设计模式 - 适配器模式

    概念: 将一个类的接口,转换成客户期望的另一个接口.适配器模式让原来接口不兼容的类可以在一起工作. 解决的问题: 提供类似于中间人的作用:把原本不兼容.不能一起工作的接口组合在一起,使得它们能够在一起 ...

  5. Java设计模式——适配器模式(Adapter)

    目的:把源类型适配为目标类型,以适应客户端(Client)的需求:此处我们把目标接口的调用方视为客户端 使用场景:需要对类型进行由源类型到目标类型转换的场景中 前置条件:已有客户端 //Client ...

  6. java设计模式——适配器模式 Java源代码

    前言:适配器模式就是把一个类的接口变换成客户端所能接受的另一种接口,从而使两个接口不匹配而无法在一起工作的两个类能够在一起工作.通常被用在一个项目需要引用一些开源框架来一起工作时,这些框架的内部都有一 ...

  7. Java设计模式の适配器模式

    定义 适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作. 适配器模式的用途 用电器做例子,笔记本电脑的插头一般都是三相的,即除了阳极 ...

  8. Java设计模式-适配器模式(Adapter)

    适配器模式将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题.主要分为三类:类的适配器模式.对象的适配器模式.接口的适配器模式.首先,我们来看看类的适配器模 ...

  9. Java设计模式—适配器模式

    适配器模式的个人理解: 首先有一个目标角色.一个源角色还有一个适配器角色.我们要做的就是利用适配器角色将源角色转换为目标角色.而目标角色是一个正在良好运行的一个角色. 转换方法: (1)  适配器类继 ...

随机推荐

  1. 2021-2-27:Linux 下如何优化 Java MMAP 写入

    主要是调整 pdflush 相关参数. 在linux操作系统中,写操作是异步的,即写操作返回的时候数据并没有真正写到磁盘上,而是先写到了系统cache里,随后由pdflush内核线程将系统中的脏页写到 ...

  2. Android 7.0 TextView点击事件无效修复方案

    public class PostTextView extends TextView { private Handler handler = new Handler(Looper.getMainLoo ...

  3. 基于SaaS平台的iHRM项目的前端项目介绍

    1.下载安装node.js 访问https://nodejs.org/en/,然后下载安装即可 2. 查看是否安装成功 打开cmd命令行,输入node -v 如果出现对应的版本号,即为安装成功 3.从 ...

  4. SpringBoot启动报错 Disconnected from the target VM, address: '127.0.0.1:2227', transport: 'socket'

    今天搭建了一个SpringBoot项目,刚启动就报错 Disconnected from the target VM, address: '127.0.0.1:2227', transport: 's ...

  5. 关于VsCode创建Vue基础项目的步骤以及相关问题

    项目创建步骤: 1.  全局安装vue-cli 安装命令: npm install -g vue-cli 在vscode上打开一个终端,然后输入此命令(下为截图): 2. 安装webpack,打包js ...

  6. c#(NPOI)DataTable导出execl,execl(支持解析公式)导入DataTable

    NPOI(C#)DataTable导出execl using NPOI.HSSF.UserModel; using NPOI.SS.UserModel; using NPOI.XSSF.UserMod ...

  7. FPGA的开发板

    板卡架构 板载FPGA(K7-325T)处理24端口10/100/1000M以太网数据: FPGA外挂4Gbit的DDR3颗粒,最大支持800MHz: 板载CPU进行系统配置.管理,并与客户端软件通信 ...

  8. Linux 文件和目录管理

    绝对路径:路径的写法一定由根目录/写起的,例如 /usr/local/mysql 相对路径:和绝对路径相反 不是由根目录/写起的,例如用户首先进入到/home,然后进入test 执行命令:cd /ho ...

  9. Python内置函数作用及解析

    Python内置的函数及其用法.为了方便记忆,已经有很多开发者将这些内置函数进行了如下分类: 数学运算(7个)    类型转换(24个)    序列操作(8个)    对象操作(7个)    反射操作 ...

  10. P1426 小鱼会有危险吗(JAVA语言)

    题目描述 有一次,小鱼要从A处沿直线往右边游,小鱼第一秒可以游7米,从第二秒开始每秒游的距离只有前一秒的98%.有个极其邪恶的猎人在距离A处右边s米的地方,安装了一个隐蔽的探测器,探测器左右x米之内是 ...