指方画圆之Java设计模式:适配器模式
应用场景
使用者依赖的接口与提供者的接口不匹配时,就加一层适配,而不修改两端的代码
生活中使用的风扇,假设插头是两孔的,但是我们家里墙上的插座只有三孔的,这个时候就需要一个适配器了,这个适配器就是外面买的插座,以上场景为例,写一个例子:
三孔的插座:
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();
}
}

类图:

适配器模式
定义
把一个类的接口变成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作
意图
将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作
主要解决问题
要解决在软件系统中,常常要将一些"现存的对象"放到新的环境中,而新环境要求的接口是现对象不能满足的
何时使用
- 系统需要使用现有的类,而此类的接口不符合系统的需要
- 想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有一致的接口
- 通过接口转换,将一个类插入另一个类系中
优缺点
优点:
- 可以让任何两个没有关联的类一起运行
- 提高了类的复用
- 增加了类的透明度
- 灵活性好
缺点:
- 过多地使用适配器,会让系统非常零乱,不易整体进行把握
- 由于JAVA至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类
类图:

涉及到的角色:
- 目标(Target)角色:这就是所期待的接口,目标可以是具体的或抽象的类
- 源(Adaptee)角色:现有需要适配的接口
- 适配器(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设计模式:适配器模式的更多相关文章
- Java设计模式——适配器模式
JAVA 设计模式 适配器模式 用途 适配器模式 (Adapter) 将一个类的接口转换成客户希望的另外一个接口. Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 适配器 ...
- 【设计模式】Java设计模式 - 适配器模式
[设计模式]Java设计模式 - 适配器模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 原创作品,更多关注我CSDN: 一个有梦有戏的人 准备将博客园.CSDN一 ...
- JAVA 设计模式 适配器模式
用途 适配器模式 (Adapter) 将一个类的接口转换成客户希望的另外一个接口. Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 适配器模式是一种结构型模式. 结构
- Java设计模式 - 适配器模式
概念: 将一个类的接口,转换成客户期望的另一个接口.适配器模式让原来接口不兼容的类可以在一起工作. 解决的问题: 提供类似于中间人的作用:把原本不兼容.不能一起工作的接口组合在一起,使得它们能够在一起 ...
- Java设计模式——适配器模式(Adapter)
目的:把源类型适配为目标类型,以适应客户端(Client)的需求:此处我们把目标接口的调用方视为客户端 使用场景:需要对类型进行由源类型到目标类型转换的场景中 前置条件:已有客户端 //Client ...
- java设计模式——适配器模式 Java源代码
前言:适配器模式就是把一个类的接口变换成客户端所能接受的另一种接口,从而使两个接口不匹配而无法在一起工作的两个类能够在一起工作.通常被用在一个项目需要引用一些开源框架来一起工作时,这些框架的内部都有一 ...
- Java设计模式の适配器模式
定义 适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作. 适配器模式的用途 用电器做例子,笔记本电脑的插头一般都是三相的,即除了阳极 ...
- Java设计模式-适配器模式(Adapter)
适配器模式将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题.主要分为三类:类的适配器模式.对象的适配器模式.接口的适配器模式.首先,我们来看看类的适配器模 ...
- Java设计模式—适配器模式
适配器模式的个人理解: 首先有一个目标角色.一个源角色还有一个适配器角色.我们要做的就是利用适配器角色将源角色转换为目标角色.而目标角色是一个正在良好运行的一个角色. 转换方法: (1) 适配器类继 ...
随机推荐
- react性能提升
1.把.bind(this)提升到constructor里面 2.在生命周期函数里面shouldComponentupdate里面做父组件改变重新渲染以致于子组件重新渲染的禁止 3.在setstate ...
- mybatisPlus中的模糊查询问题
不能查询中文 记得在数据库的配置中写明编码格式characterEncoding=utf-8
- Vue学习笔记-chrome84版本浏览器跨域设置
一 使用环境: windows 7 64位操作系统 二 chrome84版本浏览器跨域设置 报错问题:Indicate whether to send a cookie in a cross- ...
- DQL:data query language用来查询数据库表中的数据
对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 如果没有查询条件,则每次查询所有的行.实际应用中,一般要指定查询的条件.对记录进行过滤. 查询 ...
- 零信任三大技术之SDP
SDP概述 SDP Software Defined Perimeter(软件定义边界),2013 年由云安全联盟 CSA提出. SDP 设计基本原则 1.信息隐身:隐藏服务器地址.端口,使之不被扫描 ...
- C#语言特性及发展史
本文按照C#语言的发展历史,介绍C#每个版本的新增特性,主要参考微软官方文档.了解这些语言特性可以帮助我们更高效的编写C#代码. C# 1.0 与Visual Studio .NET 2002一起发布 ...
- FFT HDL Optimized模块HDL综合代码生成及与Xilinx xfft IP MEX接口精度详细比较
前面一篇随笔叙述了关于MATLAB中FFT_HDL_Optimzed模块定点(IEEE754单精度float格式)二进制与十进制转换实现,有需要的往前翻一下即可.这一篇随笔将叙述 FFT HDL Op ...
- pytorch(10)transform模块(进阶)
图像变换 Pad 对图片边缘进行填充 transforms.Pad(padding,fill=0,padding_mode='constant') padding:设置填充大小,(a,b,c,d)左上 ...
- python工业互联网应用实战7—业务层
本章我们演示代码是如何"进化"的,实战的企业日常开发过程中,系统功能总伴随着业务的不断增加,早期简单的代码慢慢的越来越复杂,敏捷编程中的"禅"--简单设计.快速 ...
- Java 在PPT中添加文本水印的简易方法(单一/平铺水印)
[前言] 在PPT幻灯片中,可通过添加形状的方式,来实现类似水印的效果,可添加单一文本水印效果,即在幻灯片中心位置水印以单个文本字样显示,但通过一定方法也可以添加多行(平铺)文本水印效果,即在幻灯片中 ...