指方画圆之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) 适配器类继 ...
随机推荐
- js---it笔记
typeof a返回的是字符串 vscode scss安装的easy scss中的配置settingjson文件中的css编译生成路径是根目录下的
- 【转载】Win10彻底格式化磁盘防止数据恢复的技巧
转载地址 注意 要尽量删除数据,请在运行cipher /w时关闭其他所有应用程序. 1.如果你在格式化磁盘后想要防止数据被恢复, Format 命令,而现在只需在其后添加 /P 参数,即可用随机数据覆 ...
- 微信小程序:添加全局的正在加载中图标效果
在发送请求的时候,显示一个正在加载中的小图标.在加载下一页的时候也显示正在加载中.同时数据请求回来了,把加载中进行关闭. 开发----API-----界面 在哪里添加这两段代码会比较方便呢?一个项目有 ...
- IDEA如何快速查看类中的属性和方法?
在idea中,当需要快速的查看一个类的所有属性和方法时,直接去代码中查看,就显得非常的麻烦,idea是有快捷键的,可显示所有的属性和方法,方法如下. 打开一个类,使用快捷键ALT+7,就可以在左侧看到 ...
- SpringBoot自定义注解
1.注解的概念 注解是一种能被添加到java代码中的元数据,类.方法.变量.参数和包都可以用注解来修饰.注解对于它所修饰的代码并没有直接的影响. 2.注解的使用范围 1)为编译器提供信息:注解能被编译 ...
- 使paramiko库执行命令时,在给定的时间强制退出
原因: 使用paramiko库ssh连接到远端云主机上时,非常偶现卡死现象,连接无法退出(可以是执行命令时云主机重启等造成).需要给定一段时间,不管命令执行是否卡住,都退出连接,显示命令执行超时错误. ...
- 破解MySQL库user表hash密码
目录 得到用户名和密码 hash 带*和不带*的区别 破解hash 在线工具 Hashcat 实验环境 select version(); 得到用户名和密码 hash mysql安装好就会默认生成图中 ...
- MySQL基本指令3 和 索引 、分页
1视图: -创建 create view 视图名称 as SQL ps:虚拟 -修改 alter view 视图名称 as SQL -删除 drop view 视图名称 2触发器 3自定义函 ...
- go中sync.Once源码解读
sync.Once 前言 sync.Once的作用 实现原理 总结 sync.Once 前言 本次的代码是基于go version go1.13.15 darwin/amd64 sync.Once的作 ...
- CloudQuery v1.3.4 版本更新
Hello,大家好久不见! 上一个版本(v1.3.3)发布已是春节前的事情了,此次 v1.3.4 是 CloudQuery 社区版在辛丑牛年的第一个版本发布.本次更新增加了新功能,优化了原有功能点.同 ...