应用场景

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

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

三孔的插座:

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. 《Activity显示界面历险记》—说说View的那些理不清的关系

    前言 在Activity显示View的过程中,有一些重要的角色总让人理不清,比如PhoneWindow.DecorView.ViewRootImpl. 也常常有面试题会问到,他们四者之间的关系?创建的 ...

  2. 下载com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

    看别人都说在repo.maven.com下载,没想到竟然要登录 索性我直接在国内阿里云的镜像仓库下载好了,速度又快又方便 搜索aspectj 下载地址:https://maven.aliyun.com ...

  3. 从HashMap面试聊聊互联网内卷

    微信公众号:大黄奔跑 关注我,可了解更多有趣的面试相关问题. 写在之前 毫无疑问,回想2020年有什么词出现在眼前最多的,无疑是"996"和"内卷",从马老师的 ...

  4. 学习java之基础语法(三)

    学习java之基础语法(三) java运算符 计算机的最基本用途之一就是执行数学运算,作为一门计算机语言,Java也提供了一套丰富的运算符来操纵变量.我们可以把运算符分成以下几组: 算术运算符 关系运 ...

  5. C++对象的生存期笔记

    下面随笔记录了C++对象的生存期知识 静态生存期 这种生存期与程序的运行期相同. 在文件作用域中声明的对象具有这种生存期. 在函数内部声明静态生存期对象,要冠以关键字static . 动态生存期 块作 ...

  6. HDU1067 Gap

    题目: Let's play a card game called Gap. You have 28 cards labeled with two-digit numbers. The first d ...

  7. SpringMVC-01 什么是SpringMVC

    SpringMVC-01 什么是SpringMVC 回顾MVC 1.什么是MVC MVC是模型(Model).视图(View).控制器(Controller)的简写,是一种软件设计规范. 是将业务逻辑 ...

  8. docker在vulhub中的使用命令合集

          (1)docker  ps(查询 docker 进程的所有容器) (2)docker  info(查看docker详细信息) (3)service docker start(启动docke ...

  9. CVE-2019-20372-Nginx error_page 请求走私

    一.漏洞简介 Nginx 1.17.7之前版本中 error_page 存在安全漏洞.攻击者可利用该漏洞读取未授权的Web页面. 二.漏洞影响 Ngnix < 1.17.7 三.复现过程 错误代 ...

  10. 解决springMVC https环境 jstlview redirect时变为http请求的问题

    <property name="redirectHttp10Compatible" value="false" />