适配器形式
封装器形式
、Wrapper
、Adapter
目的
适配器形式是一种结构型规划形式, 它能使接口不兼容的方针能够相互协作。
问题
假设你正在开发一款股票市场监测程序, 它会从不同来源下载 XML 格局的股票数据, 然后向用户呈现出美观的图表。
在开发进程中, 你决定在程序中整合一个第三方智能剖析函数库。 可是遇到了一个问题, 那就是剖析函数库只兼容 JSON 格局的数据。
你无法 “直接” 运用剖析函数库, 因为它所需的输入数据格局与你的程序不兼容。
你能够修正程序库来支撑 XML。 可是, 这或许需求修正部分依靠该程序库的现有代码。 乃至还有更糟糕的情况, 你或许根本没有程序库的源代码, 然后无法对其进行修正。
处理方案
你能够创立一个适配器。 这是一个特殊的方针, 能够转化方针接口, 使其能与其他方针进行交互。
适配器形式经过封装方针将杂乱的转化进程躲藏于幕后。 被封装的方针乃至察觉不到适配器的存在。 例如, 你能够运用一个将一切数据转化为英制单位 (如英尺和英里) 的适配器封装运转于米和千米单位制中的方针。
适配器不仅能够转化不同格局的数据, 其还有助于选用不同接口的方针之间的协作。 它的运作办法如下:
- 适配器完结与其中一个现有方针兼容的接口。
- 现有方针能够运用该接口安全地调用适配器办法。
- 适配器办法被调用后将以另一个方针兼容的格局和次序将请求传递给该方针。
有时你乃至能够创立一个双向适配器来完结双向转化调用。
让我们回到股票市场程序。 为了处理数据格局不兼容的问题, 你能够为剖析函数库中的每个类创立将 XML 转化为 JSON 格局的适配器, 然后让客户端仅经过这些适配器来与函数库进行沟通。 当某个适配器被调用时, 它会将传入的 XML 数据转化为 JSON 结构, 并将其传递给被封装剖析方针的相应办法。
实在世界类比
出国游览前后的游览箱。
假如你是第一次从美国到欧洲游览, 那么在给笔记本充电时或许会大吃一惊。 不同国家的电源插头和插座规范不同。 美国插头和德国插座不匹配。 同时提供美国规范插座和欧洲规范插头的电源适配器能够处理你的难题。
适配器形式结构
方针适配器
完结时运用了构成原则: 适配器完结了其中一个方针的接口, 并对另一个方针进行封装。 一切盛行的编程语言都能够完结适配器。
- 客户端 (Client) 是包括当时程序事务逻辑的类。
- 客户端接口 (Client Interface) 描述了其他类与客户端代码协作时有必要遵循的协议。
- 服务 (Service) 中有一些功用类 (一般来自第三方或留传系统)。 客户端与其接口不兼容, 因此无法直接调用其功用。
- 适配器 (Adapter) 是一个能够同时与客户端和服务交互的类: 它在完结客户端接口的同时封装了服务方针。 适配器接受客户端经过适配器接口建议的调用, 并将其转化为适用于被封装服务方针的调用。
- 客户端代码只需经过接口与适配器交互即可, 无需与具体的适配器类耦合。 因此, 你能够向程序中添加新类型的适配器而无需修正已有代码。 这在服务类的接口被更改或替换时很有用: 你无需修正客户端代码就能够创立新的适配器类。
类适配器
这一完结运用了承继机制: 适配器同时承继两个方针的接口。 请注意, 这种办法仅能在支撑多重承继的编程语言中完结, 例如 C++。
- 类适配器不需求封装任何方针, 因为它同时承继了客户端和服务的行为。 适配功用在重写的办法中完结。 最后生成的适配器可代替已有的客户端类进行运用。
伪代码
下列适配器形式演示基于经典的 “方钉和圆孔” 问题。
让方钉适配圆孔。
适配器假扮成一个圆钉 (RoundPeg), 其半径等于方钉 (SquarePeg) 横截面对角线的一半 (即能够包容方钉的最小外接圆的半径)。
适配器形式合适应用场景
当你希望运用某个类, 可是其接口与其他代码不兼容时, 能够运用适配器类。
适配器形式允许你创立一个中间层类, 其可作为代码与留传类、 第三方类或提供怪异接口的类之间的转化器。
假如您需求复用这样一些类, 他们处于同一个承继系统, 而且他们又有了额定的一些一起的办法, 可是这些一起的办法不是一切在这一承继系统中的子类所具有的共性。
你能够扩展每个子类, 将短少的功用添加到新的子类中。 可是, 你有必要在一切新子类中重复添加这些代码, 这样会使得代码有坏滋味。
将缺失功用添加到一个适配器类中是一种高雅得多的处理方案。 然后你能够将短少功用的方针封装在适配器中, 然后动态地获取所需功用。 如要这一点正常运作, 方针类有必要要有通用接口, 适配器的成员变量应当遵循该通用接口。 这种办法同装修形式十分相似。
完结办法
- 保证至少有两个类的接口不兼容:
- 一个无法修正 (一般是第三方、 留传系统或许存在众多已有依靠的类) 的功用性服务类。
- 一个或多个将获益于运用服务类的客户端类。
- 声明客户端接口, 描述客户端如何与服务交互。
- 创立遵循客户端接口的适配器类。 一切办法暂时都为空。
- 在适配器类中添加一个成员变量用于保存对于服务方针的引证。 一般情况下会经过结构函数对该成员变量进行初始化, 但有时在调用其办法时将该变量传递给适配器会更方便。
- 依次完结适配器类客户端接口的一切办法。 适配器会将实际工作委派给服务方针, 本身只担任接口或数据格局的转化。
- 客户端有必要经过客户端接口运用适配器。 这样一来, 你就能够在不影响客户端代码的情况下修正或扩展适配器。
适配器形式优缺点
-
单一职责原则你能够将接口或数据转化代码从程序主要事务逻辑中分离。
-
开闭原则。 只要客户端代码经过客户端接口与适配器进行交互, 你就能在不修正现有客户端代码的情况下在程序中添加新类型的适配器。
-
代码全体杂乱度添加, 因为你需求新增一系列接口和类。 有时直接更改服务类使其与其他代码兼容会更简单。
代码与示例
- Golang 「适配器形式」讲解和代码示例 – 掘金 ()