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. flask源码剖析系列(系列目录)

    flask源码剖析系列(系列目录) 01 flask源码剖析之werkzurg 了解wsgi 02 flask源码剖析之flask快速使用 03 flask源码剖析之threading.local和高 ...

  2. 重学c#系列——c#运行原理(二)

    前言 c# 是怎么运行的呢?是否和java一样运行在像jvm的虚拟机上呢?其实差不多,但是更广泛. c# 运行环境不仅c#可以运行,符合.net framework 开发规范的都可以运行. c# 程序 ...

  3. bzoj4318OSU!*

    bzoj4318OSU! 题意: 一个长度为n的序列,每个元素有一定概率是1,不是1就是0.连续x个1可以贡献x^3的分数,问期望分数. 题解: 期望dp.f1[i]表示连续到i的期望长度,f2[i] ...

  4. C#中的类与对象

    类:说白了就是类型,是对具体事物的一种抽象总结. 对象:一个具体的事物. 类与对象的关系,类实例化就会得到一个对象,同样一个对象也应该属于某一个类.例如张三这个人,他是一个对象,同时他属于人类,在程序 ...

  5. JAVA集合二:HashMap和Hashtable

    参考链接: HOW2J.CN HashMap HashMap实现了JAVA的Map接口,类似于C++的STL框架的Map,是存储键值对的数据结构.键(key)是唯一的,但值(value)可以重复,如果 ...

  6. luoguP1036 选数 暴力AC题解

    luoguP1036 选数 暴力AC题解(非正解) 俗话说得好:暴力出奇迹,打表拿省一. 对于一些暴力就能拿分的题,暴力就好啦QWQ 题目描述   输入格式 输出格式 输入输出样例 定义变量 我们令输 ...

  7. EF Code 如何输出sql语句

    首先写拷贝下面类 public class EFLoggerProvider : ILoggerProvider { public ILogger CreateLogger(string catego ...

  8. 用windbg查看dmp文件,定位bug位置

    windbg + .dmp + .pdb + 源代码,可以看到是哪个代码崩溃的 设置符号文件所在路径 File->Symbol File Path... 在输入框中填入.pdb文件所在的文件夹路 ...

  9. 小白必看,Python入门你要懂那些

    Python作为为数不多的全场景开发语言之一,近年来已经获得了越来越多人的关注,而整个IT行业也释放出了大量的Python就业岗位.因此,当前学习Python语言是非常不错的选择,文泽带你进一步走进P ...

  10. time strptime()方法 时间操作

    Python time strptime()方法 时间操作   描述 Python time strptime() 函数根据指定的格式把一个时间字符串解析为时间元组. 语法 strptime()方法语 ...