适配器模式Adapter pattern, since 2024-07-04

(2024.07.04 Thur)
适配器模式是一种结构设计模式(structural design pattern),用于两种不兼容的接口做对接和交互,扮演桥的角色,允许不同接口的对象互相合作。简单来说就是改变接口。

适配器模式的主要目标是确保客户端能与不同的类或对象协作,该类/对象起初并未为该客户端设计,因此不管是客户端或是被适配的对象都不需要修改源代码即可实现交互。

组成

适配器模式可分为若干关键部分

  • Target interface目标接口:目标接口定义了客户端代码期待的接口(contarct),是适配器需要适应的接口,以确保客户端可以和被适配对象无缝沟通
  • adaptee被适配对象:与客户端的借口不兼容的类/分量,是客户端希望连接却无法直接沟通的对象,通常是第三方或遗产服务(legacy service)
  • adapter适配器:用于连接目标接口和被适配对象的中介(intermediary),将客户端的调用翻译成被适配对象可以理解和响应的形式

(2024.07.05 Fri)

优势

  • 代码复用Code reusabililty:适配器方便了代码复用,通过整合现存的类而无需改变他们的源,减少冗余度
  • 单一责任原则principle of single responsibility:适配器模式符合单一责任原则,确保了每个类有清晰和特定的角色,也因此提升了代码组织性和可维护性
  • 开闭原则Open/Closed Principle:通过适配现存的接口而非直接修改,适配器结构符合开闭原则,允许在不修改现有代码的情况下扩展代码,提升系统稳定性
  • 第三方代码整合:在使用外部库或API的时候,适配器模式方便了他们的整合,保护了代码免于被外部改变,也使得外部的升级带来的影响最小

劣势

  • 复杂度:适配器会增加代码复杂度,影响代码可维护度
  • 性能overhead:加入的适配层可以引入些许性能overhead,对高性能应用是一个隐患
  • 实际的影响:适配器的使用可能产生原始的设计问题,对于接口的不兼容性需要考虑重构

实现方式

适配器的实现方式有两种,1) 对象适配器,2) 类适配器

对象适配器Object Adapter Implementation

先定义一个原始系统

class OldSystem:
    def legacy_operation(self):
        return "legacy operation"

定义适配器

class Adapter:
    def __init__(self, old_system: OldSystem):
        self.old_system = old_system
    def new_operation(self):
        return f"Adapter: {self.old_system.legacy_operation()}"

定义客户端

def client_code(adapter: Adapter):
    result = adapter.new_operation()
    print(result)

运行代码

if __name__ == "__main__":
    old_system = OldSystem()
    adapter = Adapter(old_system)
    client_code(adapter)

返回结果

Adapter: legacy operation

本案例中,创建了一个Adapter类,该类以OldSystem对象作为输入,并提供了一个方法new_operation,该方法符合目标接口。client_code方法演示了适配器如何允许客户端与OldSystem无缝衔接。

类适配器Class Adapter

目标适配器往往作为一个常用的实现方式,而类适配器提供了另一个可行方案。在这个案例中,使用多继承(multiple inheritance)实现适配器行为。

定义OldSystem

class OldSystem:
    def legacy_operation(self):
        return "Legacy operation"

通过继承方式定义适配器,

class Adapter(OldSystem):
    def new_operation(self):
        return f"Adapter: {self.legacy_operation()}"

定义客户端

# Client code
def client_code(adapter: Adapter):
    result = adapter.new_operation()
    print(result)

运行代码

if __name__ == "__main__":
    adapter = Adapter()
    client_code(adapter)

返回结果

Adapter: Legacy operation

在这个实现的版本中,AdapterOldSystem类和目标接口继承,可覆盖legacy_operation方法以实现适配行为,而client_code可保持不变。

对象适配器和类适配器各有优势和妥协,而对两种适配器选择取决于特定的需求和项目的限制。

案例

一个案例是用Python的list实现stack的数据结构

stack方法 Python list的实现
S.push(e) L.append(e)
S.pop() L.pop()
S.top() L[-1]
S.is_empty() len(L) == 0
len(S) len(L)

具体实现

class ArrayStack:
    """LIFO Stack implementation using a Python list as underlying storage."""

    def __init__(self):
        """Create an empty stack."""
        self._data = []  # nonpublic list instance

    def __len__(self):
        """Return the number of elements in the stack."""
        return len(self._data)

    def is_empty(self):
        """Return True if the stack is empty."""
        return len(self._data) == 0

    def push(self, e):
        """Add element e to the top of the stack."""
        self._data.append(e)  # new item stored at end of list

    def top(self):
        """Return (but do not remove) the element at the top of the stack.
        Raise Empty exception if the stack is empty."""
        if self.is_empty():
            raise Empty("Stack is empty")
        return self._data[−1]  # the last item in the list

    def pop(self):
        """Remove and return the element from the top of the stack (i.e., LIFO).

        Raise Empty exception if the stack is empty."""
        if self.is_empty():
            raise Empty("Stack is empty")
        return self._data.pop()  # remove last item from list

Reference

  1. Medium, Amir Lavasani
  2. Data Structures and Algorithms in Python
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,137评论 6 511
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,824评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,465评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,131评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,140评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,895评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,535评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,435评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,952评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,081评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,210评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,896评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,552评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,089评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,198评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,531评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,209评论 2 357

推荐阅读更多精彩内容