应用场景

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

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

三孔的插座:

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. React组件复用的方式

    React组件复用的方式 现前端的工程化越发重要,虽然使用Ctrl+C与Ctrl+V同样能够完成需求,但是一旦面临修改那就是一项庞大的任务,于是减少代码的拷贝,增加封装复用能力,实现可维护.可复用的代 ...

  2. 【随便写写】印象笔记,WordPress,CSDN 等 写博客的不同

    之前有的文章,写在了印象笔记里面,有的文章,写在了自己的WordPress博客里面,但是,感觉还是需要在主流平台分享一下文章的.就再次写写文章吧.(PS:公众号最重要的不是写作,而是排版) 说说几个这 ...

  3. PowerDesigner 设计数据库中常用脚本

    PowerDesigner 设计数据库中常用脚本 数据库设计 物理模型设置 Name转Comment脚本 '********************************************** ...

  4. 如果要是把标记为2的那一行Lable1.Text改为其他的Lable显示执行代码

    转: 如果要是把标记为2的那一行Lable1.Text改为其他的Lable显示执行代码 如图,程序很简单,文件路径也没问题,为什么会报错,百思不得其解?[url]https://book.douban ...

  5. 公钥基础设施PKI利用SRAM物理不可克隆函数PUF实现芯片标识唯一性

    下面给出PKI利用SRAM PUF实现芯片标识唯一性的方法思路: PKI利用SRAM PUF实现芯片标识唯一性的方式 (1)使用PUF原因 物理上不可克隆函数利用硅制造的自然变化来产生每个芯片统计上唯 ...

  6. 基于OpenSSL的PKI的PKI数字证书系统实现

    本篇主要介绍了基于OpenSSL的PKI的PKI数字证书系统实现,利用OpenSSL建立一个CA中心的详细解决方案和建立的具体步骤. 1.PKI数字证书系统设计 PKI数字证书系统主要包括证书颁发机构 ...

  7. POJ-2406(KMP+字符串压缩)

    Power String POJ-2406 字符串压缩模板题,但是是求有多少个这样最短的子串可以组成s. #include<iostream> #include<cstring> ...

  8. bouncycastle中添加HMAC-SM3支持

    一. 最近看完了PKCS#5中的内容,总结一下自己添加HMAC-SM3中遇到的问题和解决方法. 大概通读BC java源码以后,开始上手修改. 在SM3.java中添加如下代码: /** * SM3 ...

  9. LNMP配置——Nginx配置 —— Nginx解析PHP

    一.配置 #vi /usr/local/nginx/conf/vhost/test.com.conf 写入: server { listen 80; server_name test.com test ...

  10. js 判断 是否在当前页面

    1.使用visibilitychange 浏览器标签页被隐藏或显示的时候会触发visibilitychange事件. document.addEventListener("visibilit ...