前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >设计模式(七): 通过转接头来观察"适配器模式"(Adapter Pattern)

设计模式(七): 通过转接头来观察"适配器模式"(Adapter Pattern)

作者头像
lizelu
发布2018-01-11 11:29:15
6070
发布2018-01-11 11:29:15
举报
文章被收录于专栏:青玉伏案青玉伏案

在前面一篇博客中介绍了命令模式”(Command Pattern),今天博客的主题是“适配器模式”(Adapter Pattern)。适配器模式用处还是比较多的,如果你对“适配器模式”理解呢,那么自然而然的就会知道其使用场景。今天这篇博客我们就举一个生活中的使用适配器模式的示例,然后将该示例使用代码进行表示出来,那么我们所实现的代码使用的设计模式就是我们今天所说的“适配器模式”。

“适配器”其实说白了就是一个转接头,比如Mac Book Pro 要接外接显示器,如果你没有HDMI传输线的话,那么你就得使用转接头作为中间件来连接外接显示器。你观察各种“转接头”他们都有一个共同的特点,就是转接头两端的接口肯定是不一样的。其实上面我说了句废话了,如果转接头的两端一致那么就是传输线了就不是转接头了。其实我们今天所要介绍的“适配器模式”就来源生活中的各种适配器。适配器说白了,其职责就是将一种接口转换成另一种接口。下方是生活中常见的适配器。

上面说这么多了,那么让我们来看一下“适配器模式”的定义吧,下方是适配器模式的定义:

适配器模式:将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间

接下来我们就拿生活中的一个示例来真正的感受一下适配器模式。作为一个Programer你肯定使用过笔记本电脑,在此就使用MacBook Pro的电源适配器来做类比。MacBook Pro中接入外接电源时需要电源适配器的,接下来我们就使用代码来实现插座,适配器以及MacBook Pro和其自带电池间的关系。

一、电源适配器中的类图

接下来我们将给出MacBook Pro电源适配器中的使用代码表示的类图,也就是我们使用“适配器模式”来设计电源适配器时所使用的类图。下方就是我们所使用的类图,总体看来下方的类图分为三个模块,左边的红框是我们的插座,中间的黄框是我们的电源适配器,右边的绿框就是我们经常使用的笔记本电脑了。在笔记本电脑中带有电池,MacBook Pro使用自带电池是不需要适配器的,因为该电池在设计之初就是为其设计的。但是如果MacBook Pro的电池没有电了,我们就需要为其接入外部电源。因为外部电源是多种多样的,电压电流都有所不同,不能直接给MacBook Pro供电,所以需要电源适配器来为MacBook Pro供电。下图中黄色的就是我们的电源适配器,也是适配器模式的核心。依次给出了每个模块的的介绍,如下所示:

在下方类图中的红色部分就是我们模拟插座的模块。在该模块中含有一个SocketType协议,该协议是Socket(插座)的一种规范,在此我们可以暂且理解为插座的国标。其中定义了插座的统一规范,只给出了声明没有实现(只给出了插座的尺寸,没有给出如何生产插座)。我们要实现的Socket都遵循于SocketType协议,也就是说在中国生产的插座要符合中国国标,在美国生产的插座当然要符合美国的国标,当然这两者的插座标准有可能是一样的。红框中就模拟了我们的插座。

接下来我们来看一下绿框中的内容。绿框中就是我们的MacBook Pro,其中也有个协议,名为ComputerPowerSourceType。该协议是笔记本电脑?的供电系统协议,只要是遵循该协议(接口)的电源都可以给MacBook Pro供电。因为从下方的类图我们可以看出,MacBook Pro是依赖于供电系统的协议的而不是依赖于具体实现,所以笔记本电脑的自带电池是可以进行更换的,而且可以外接电源。但是外接电源也得必须要遵循MacBook Pro中的ComputerPowerSourceType协议。接下来就是适配器出厂的时候了。

要使用插座给MacBook Pro供电必须得用适配器,你不能直接拿根线捅上完事儿,这样会出问题的。接下来就是电源适配器出场的时候了,下方黄框中的就是电源适配器。当然黄框中一个类是一个适配器,也就是黄框中是两个适配器。不过这两个适配器实现方式不同,也就是不同类型的适配器,但都可以连接插座给MacBookPro进行供电。两者的具体不同之处会在具体实现的时候给出详细的解释。无论使用哪个电源适配器,我们的MacBook Pro就可以接上插座来工作了。这两个适配器因为一方要连接MacBookPro,所以都实现了ComputerPowerSourceType协议,这样适配器的一端连接MacBook Pro就不成问题了。除了连接MacBook Pro外,你还得对插座输出的电压等进行处理,从而MacBook Pro可以使用处理后的电压电流等。因为初始电流是插座提供的,所以适配器为了处理电压和电流还需要还需要继承或者依赖于插座。依赖插座的适配器我们称之为“对象适配器”(插座是适配器中的一个对象),继承自插座的适配器我们称之为“类适配器”(插座是适配器中的父类)。具体请看下方的代码实现。

二、电源适配器的具体实现

接下来就到了我们代码实现的时候了,还是那句话,只要思路有了实现应该是问题不大的。上面的类图就是我们的思路,我们在代码实现时,就是将上面的类图转换成具体的代码实现。当然本篇博客仍然使用的是Swift语言来实现的,当然你也可以使用其他你熟悉的任何面向对象语言来实现。接下来就一步步的将上述类图转变成具体的代码实现。下方先给出了插座模块的实现,然后给出了MacBook Pro的实现,最后给出了两种电源适配器的实现,具体请参见下方内容。

1.插座模块的实现

我们先对插座模块进行实现,对应着上方类图中红色的部分,也就是对SocketType协议以及Socket类进行具体代码实现,当然在实现Socket类时要遵循SocketType协议。SocketType协议中的socketOutputVoltage() -> Float 负责电压输出的,为了简化我们的代码复杂度,将重点放在适配器上,在此我们只实现了socketOutputVoltage() -> Float这一个方法,其余插座的方法我们在此进行省略掉。

下方代码中就是插座模块的具体实现,Socket(插座)遵循了SocketType(插座协议),并且实现了SocketType中的socketOutputVoltage()方法。在该方法中返回了插座的输出电压,我们常用的插座输出的电压是220.0V,所以在该函数中就返回220.0,具体实现如下所示:

2.MacBook Pro的代码实现

在下方代码中是对MacBook Pro模块的实现,对应这上方类图中的绿色部分。下方首先我们给出类计算机电源的接口协议,也就是ComputerPowerSourceType。凡是给MacBook Pro供电的设备都必须遵循这个协议,该协议中的outputVoltage() -> Float所提供的电压就是我们MacBook Pro所需的电压。我们的MacBook Pro的实现类依赖于ComputerPowerSourceType协议。

紧接着我们给出了MacBook Pro的自带电池的实现,即MacBookProBattery类。MacBookProBattery类遵循与ComputerPowerSourceType协议,这样这块电池才能给MacBook Pro供电。在MacBookProBattery类的outputVoltage()方法中返回了MacBook Pro所需的电压,如下代码段所示。

下方代码段的最下方的类是我们的MacBook Pro类,其中依赖于ComputerPowerSourceType协议。也就是说只要是遵循ComputerPowerSourceType协议的电源都可以给我们的计算机供电。在MacBookPro中的inputVoltage()方法中调用了实现ComputerPowerSourceType协议的对象的outputVoltage()方法,如下所示。

3. 电源适配器的代码实现

如果没有适配器,MacBookPro就只能使用MacBookProBattery(自带电池),而无法使用Socket(插座),要想MacBookPro也可以使用Socket进行供电就必须有“适配器”进行转换。上面两部分都是为该部分准备的,如果要将上面两部分进行连接,也就是使用插座给MacBook Pro进行供电,就需要本部分的适配器。该部分是“适配器模式”的核心,该部分是代码实现也是根据上述类图中黄色的部分进行实现的。在该部分会分别给出“类适配器”与“对象适配器”,具体内容请看下方详细代码片段。

下方的适配器都有一个共同点,因为其是笔记本电脑的适配器所以都遵循了ComputerPowerSourceType协议。也就是说他们都可以插入MacBook Pro进行供电,这是两个适配器一致的地方。至于该适配器可以插入哪一种插座,那么要看起适配器类型了。

(1). “对象适配器”的代码实现

之所以称之为“对象适配器”,是因为该适配器中还有一个插座的对象。该插座的对象是通过SocketType来声明的,也就是说这个插座对象可以是多种类型的插座,但前提是这些插座必须遵循SocketType协议即可。进一步说,“对象适配器”依赖于插座的接口而不依赖于插座的具体实现,这一点需要注意,因为这一点与“类适配器”不同,下方会给出比较。

在“对象适配器”MacPowerObjectAdapter中的insertSocket()的方法就是为该适配器指定特定的插座的,也是适配器插入插座的过程,这个插座只需要符合SocketType协议即可。在该适配器中还实现了ComputerPowerSourceType协议中的outputVoltage()方法,适配器就是通过该方法给MacBook Pro供电的。在该方法中对插座提供的电压进行了处理,使其可以适用于我们的MacBook Pro,具体实现如下所示:

(2). "类适配器"的代码实现

上面给出了“对象适配器”的实现,紧接着我们还会给出“类适配器”的代码实现。上面已经提到,对象适配器与类适配器都实现了ComputerPowerSourceType协议。但其两者的不同在于对象适配器是依赖于SocketType接口,也就是依赖于某个Socket对象,所以称为对象适配器。而类适配器则是继承在某个特定的插座的类,也就是“类适配器”依赖于Socket类的具体实现,所以称为“类适配器”

换句话说,就是“对象适配器”依赖于接口,而“类适配器”依赖于具体实现。所以根据我们之前所说的设计模式规则中的“依赖于接口,而不依赖于具体实现”的规则就可以看出那种适配器的可扩展性更好一些。下方的MacPowerClassAdapter适配器就是“类适配器”,该类适配器不仅仅遵循了ComputerPowerSourceType协议,还继承了Socket类,如下所示。

三、测试用例

根据我们的类图,经过上面这部分,我们给出了具体的代码实现。在该代码实现中我们分别给出了插座接口以及插座的实现、MacBook Pro以及电池和电池接口的实现、两种适配器的实现。接下来测试的时间到了,下方给出了我们该如何使用适配器在MacBook Pro和插座间进行对接。

1. 创建各种实例

首先我们先创建我们测试用例所需的实例对象,下方代码段创建了MacBook Pro的对象macBookPro,MacBook Pro所用电池的对象macBookProBattery,插座的对象socket,以及“对象适配器”的对象macBookProObjectAdapter和“类适配器”的对象macBookProClassAdapter。如下所示:

2. 使用上述对象

上面已经创建了我们测试用例所需要的所有对象,接下来让我们来进行测试。首先我们先使用电池来为我们的MacBook供电,如下所示:

使用MacBook Pro自带的电池是不需要使用我们定义的适配器的,不过当电池没电时,我们需要接入外接电源,此时我们需要使用我们的适配器了。下方使用了我们的对象适配器。先将适配器接入插座(为适配器指定插座对象),然后MacBook Pro接入适配器,然后就可以供电了。使用方式如下所示:

接下来是类适配器出场的时候了,下方的代码是使用“类适配器”的内容。因为类适配器以及确定要使用哪种类型的插座,所以不需要为其指定插座的特定类型。代码如下:

3. 测试用例输出结果

从输出结果可以看出,无论通过哪种方式供的电,虽然插座提供的电压是220V, 但是我们的MacBook Pro所获取的电压都是16.5,如下所示。

至此今天的博客就写完了,仔细阅读完本篇博客后我们应该对“适配器模式”有深入的了解。

今天博客中的代码仍然会在Github上进行分享,分享地址为:https://github.com/lizelu/DesignPatterns-Swift

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016-04-28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
消息队列 TDMQ
消息队列 TDMQ (Tencent Distributed Message Queue)是腾讯基于 Apache Pulsar 自研的一个云原生消息中间件系列,其中包含兼容Pulsar、RabbitMQ、RocketMQ 等协议的消息队列子产品,得益于其底层计算与存储分离的架构,TDMQ 具备良好的弹性伸缩以及故障恢复能力。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档