1、什么是适配器模式?

适配器如同一个常见的变压器,也如同电脑的变压器和插线板之间的电源连接线,他们虽然都是3相的,但是电脑后面的插孔却不能直接插到插线板上。

如果想让额定工作电压是直流12伏特的笔记本电脑在交流100伏特”的AC电源下工作,应该怎么做呢?通常,我们会使用AC适配器,将家庭用的交流100伏特电压转换成我们所需要的直流12伏特电压。这就是适配器的工作,它位于实际情况与需求之间,填补两者之间的差异。适配器的英文是Adapter,意思是.....相互适合的东西”。前面说的AC适配器的作用就是让工作于直流12伏特环境的笔记本电脑适合于交流100伏特的环境(如下图)。

在程序世界中,经常会存在现有的程序无法直接使用,需要做适当的变换之后才能使用的情况。这种用于填补“现有的程序”和“所需的程序”之间差异的设计模式就是Adapter模式。Adapter模式也被称为Wrapper模式。Wrapper有 “包装器”的意思,就像用精美的包装纸将普通商品包装成礼物那样,替我们把某样东西包起来,使其能够用于其他用途的东西就被称为“包装器”或是“适配器”。

Adapter模式有以下两种。

●类适配器模式(使用继承的适配器) ●对象适配器模式(使用委托的适配器)

本章将依次学习这两种Adapter模式。

2、适配器样例

首先定义一个Banner类,比如就是我们实际的情况.

package cn.design.adapter;

/**
* @author lin
* @version 1.0
* @date 2020-07-14 11:21
* @Description TODO
*/
public class Banner {    private String string;    public Banner(String string) {
       this.string = string;
  }    public void showWithParen() {
       System.out.println("(" + string + ")");
  }    public void showWithAster() {
       System.out.println("*" + string + "*");
  }
}

定义一个Print接口, 是需求的接口

package cn.design.adapter;

/**
* @author lin
* @version 1.0
* @date 2020-07-14 11:24
* @Description TODO
*/
public interface Print {
   public abstract void printWeak();    public abstract void printStrong(); }

2.1、类适配器模式

定义一个PrintBanner类,扮演适配器的角色 它继承Banner并且实现Print接口.

package cn.design.adapter;

/**
* @author lin
* @version 1.0
* @date 2020-07-14 11:25
* @Description TODO
*/
public class PrintBanner extends Banner implements Print {    public PrintBanner(String string) {
       super(string);
  }    @Override
   public void printWeak() {
       showWithParen();
  }    @Override
   public void printStrong() {
       showWithAster();
  }
}

Main测试类

package cn.design.adapter;

/**
* @author lin
* @version 1.0
* @date 2020-07-14 11:26
* @Description TODO
*/
public class Main1 {
   public static void main(String[] args) {
       PrintBanner p1 = new PrintBanner("hello world");
       p1.printWeak();
       p1.printStrong();
  }
}

运行结果如下:

(hello world)
*hello world*

2.2、对象适配器模式

定义一个BasePrint抽象类

package cn.design.adapter;

/**
* @author lin
* @version 1.0
* @date 2020-07-14 11:24
* @Description TODO
*/
public abstract class BasePrint {
   public abstract void printWeak();    public abstract void printStrong(); }

定义一个PrintBanner2类,它继承BasePrint

package cn.design.adapter;

/**
* @author lin
* @version 1.0
* @date 2020/7/14 22:10
* @Description TODO
*/
public class PrintBanner2 extends BasePrint {
   Banner banner;    public PrintBanner2(String string) {
       this.banner = new Banner(string);
  }    @Override
   public void printWeak() {
       banner.showWithParen();
  }    @Override
   public void printStrong() {
       banner.showWithAster();
  }
}

定义Main2测试类

package cn.design.adapter;

/**
* @author lin
* @version 1.0
* @date 2020/7/14 22:11
* @Description TODO
*/
public class Main2 {
   public static void main(String[] args) {
       PrintBanner2 p2 = new PrintBanner2(" main2 ");
       p2.printWeak();
       p2.printStrong();
  }
}

运行结果如下:

( main2 )
* main2 *

3、适配器的登场角色

类适配器模式:

对象适配器模式

◆Target(对象)

该角色负责定义所需的方法。以本章开头的例子来说,即让笔记本电脑正常工作所需的直流12伏特电源。在示例程序中,由Print接口(使用继承时)和Print类(使用委托时)扮演此角色。

◆Client (请求者)

该角色负责使用Target 角色所定义的方法进行具体处理。以本章开头的例子来说,即直流12伏特电源所驱动的笔记本电脑。在示例程序中,由Main类扮演此角色。

◆Adaptee (被适配)

注意不是Adapt-er (适配)角色,而是Adapt-ee (被适配)角色。Adaptee是-一个持有既定方法的角色。以本章开头的例子来说,即交流100伏特电源。在示例程序中,由Banner类扮演此角色。如果Adaptee角色中的方法与Target角色的方法相同(也就是说家庭使用的电压就是12伏特直流电压),就不需要接下来的Adapter角色了。

◆Adapter (适配)

Adapter模式的主人公。使用Adaptee角色的方法来满足Target 角色的需求,这是Adapter 模式的目的,也是Adapter角色的作用。以本章开头的例子来说,Adapter 角色就是将交流100伏特电压转换为直流12伏特电压的适配器。在示例程序中,由PrintBanner类扮演这个角色。在类适配器模式中,Adapter角色通过继承来使用Adaptee角色,而在对象适配器模式中,Adapter角色通过委托来使用Adaptee角色。

4、什么时候使用适配器?

一定会有读者认为“如果某个方法就是我们所需要的方法,那么直接在程序中使用不就可以了吗?为什么还要考虑使用Adapter模式呢?”那么,究竟应当在什么时候使用Adapter模式呢?

很多时候,我们并非从零开始编程,经常会用到现有的类。特别是当现有的类已经被充分测试过了,Bug很少,而且已经被用于其他软件之中时,我们更愿意将这些类作为组件重复利用。

Adapter模式会对现有的类进行适配,生成新的类。通过该模式可以很方便地创建我们需要的方法群。当出现Bug时,由于我们很明确地知道Bug不在现有的类( Adaptee角色)中,所以只需调查扮演Adapter角色的类即可。这样一来, 代码问题的排查就会变得非常简单。

5、总结

个人经验

如何做到一个类不被实例化或者不被轻易实例化?

1.把一个类定义为抽象类;

2.把一个类的构造方法设置为:private类型的,这样在客户端就不能通过new ClassName()方法来轻易将一个类实例化,而要生成此类的实例就必须通过一个特殊的方法,这样在一个系统中,对此类的使用就能得到合理的控制(如:单例模式/多例模式/简单工厂方法等模式)。

3. 对于两个独立的系统,要满足ocp原则,则适配器模式会有一定的局限性。

发哥讲

如果你觉得文章还不错,就请点击右上角选择发送给朋友或者转发到朋友圈~

● 扫码关注公众号

2、适配器 adapter 模式 加个"适配器" 以便于复用 结构型设计模式的更多相关文章

  1. 11、Composite 组合模式 容器与内容的一致性(抽象化) 结构型设计模式

    1.Composite模式定义 组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象.组合模式依据树形结构来组合对象,用来表示部分以及整体层次.这 ...

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

    今天学习另一个设计模式,适配器(Adapter)模式,这是一个共同方向,但有特殊要求,就应用到此设计模式.写到这里,想起很久以前,有写过一篇<ASP.NET的适配器设计模式(Adapter)&g ...

  3. 【原】模式之-适配器Adapter模式

    适配器Adapter模式 适配器模式(Adapter Pattern)把一个类的接口变换成客户端所期待的的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作. 模式所涉及的角色有 ...

  4. 桥接模式 桥梁模式 bridge 结构型 设计模式(十二)

      桥接模式Bridge   Bridge 意为桥梁,桥接模式的作用就像桥梁一样,用于把两件事物连接起来   意图 将抽象部分与他的实现部分进行分离,使得他们都可以独立的发展.  意图解析 依赖倒置原 ...

  5. 适配器模式 adapter 结构型 设计模式(九)

    现实世界中的适配器模型   先来看下来几个图片,截图自淘宝 上图为港版的插头与港版的插座   上图为插座适配器卖家的描述图   上图为适配后的结果 现实世界中适配器模式 角色分类 这就是适配器模式在电 ...

  6. 代理模式 PROXY Surrogate 结构型 设计模式(十四)

    代理模式 PROXY 别名Surrogate 意图 为其他的对象提供一种代理以控制对这个对象的访问. 代理模式含义比较清晰,就是中间人,中介公司,经纪人... 在计算机程序中,代理就表示一个客户端不想 ...

  7. 享元模式 FlyWeight 结构型 设计模式(十五)

    享元模式(FlyWeight)  “享”取“共享”之意,“元”取“单元”之意. 意图 运用共享技术,有效的支持大量细粒度的对象. 意图解析 面向对象的程序设计中,一切皆是对象,这也就意味着系统的运行将 ...

  8. 组合模式 合成模式 COMPOSITE 结构型 设计模式(十一)

    组合模式(合成模式 COMPOSITE) 意图 将对象组合成树形结构以表示“部分-整体”的层次结构. Composite使得用户对单个对象和组合对象的使用具有一致性.   树形结构介绍 为了便于理解, ...

  9. java演示适配器(adapter)模式

    为什么要使用模式: 模式是一种做事的一种方法,也即实现某个目标的途径,或者技术. adapter模式的宗旨就是,保留现有类所提供的服务,向客户提供接口,以满足客户的需求. 类适配器:客户端定义了接口并 ...

随机推荐

  1. EM算法理论与推导

    EM算法(Expectation-maximization),又称最大期望算法,是一种迭代算法,用于含有隐变量的概率模型参数的极大似然估计(或极大后验概率估计) 从定义可知,该算法是用来估计参数的,这 ...

  2. 爬虫07 /scrapy图片爬取、中间件、selenium在scrapy中的应用、CrawlSpider、分布式、增量式

    爬虫07 /scrapy图片爬取.中间件.selenium在scrapy中的应用.CrawlSpider.分布式.增量式 目录 爬虫07 /scrapy图片爬取.中间件.selenium在scrapy ...

  3. css换行后缩进,css缩进技巧

    一般情况下像下图这样需要缩进的,一般都会外面一个div里面两块需要两个div然后用定位或者flex.table.浮动后设置宽度等来实现 已知宽度的情况下上面列的方法都适用 不知宽度的情况下可以用fle ...

  4. TCP 和 UDP,哪个更胜一筹

    作为 TCP/IP 中两个最具有代表性的传输层协议,TCP 和 UDP 经常被拿出来相互比较.这些协议具体有什么区别,又是什么作用呢? 在 IT 圈混迹多年的小伙伴们,对 TCP 和 UDP 肯定再熟 ...

  5. Oracle版本发布规划 (文档 ID 742060.1)

    Oracle Database Release Schedule of Current Database Releases (文档 ID 742060.1) Oracle Database RoadM ...

  6. 一张PDF了解JDK11 GC调优秘籍-附PDF下载

    目录 简介 废弃的VM选项 Source-File Mode Code Heap状态分析 AppCDS 总结 简介 JDK11相比JDK10,添加了一个新的Source-File Mode,可以直接通 ...

  7. 微信小程序 springboot nginx 做图片存储 上传 浏览

    微信小程序前端-springboot后端-nginx图片存储 前言 本人小白一名,这是第一次学习微信小程序,特此做个记录. 首先准备nginx做图片存储 选择一个地址存放图片 #我的地址 [root@ ...

  8. 剑指offo记录

    一.二维数组中的查找 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是 ...

  9. 第 13 篇:DRF 框架之 API 版本管理

    作者:HelloGitHub-追梦人物 API 不可能一成不变,无论是新增或者删除已有 API,都会对调用它的客户端产生影响.如果对 API 的增删没有管理,随着 API 的增增减减,调用它的客户端就 ...

  10. 【NeurlPS2019】Positional Normalization 位置归一化

    作者提出,当前的BatchNorm, GroupNorm, InstanceNorm在空间层面归一化信息,同时丢弃了统计值.作者认为这些统计信息中包含重要的信息,如果有效利用,可以提高GAN和分类网络 ...