声明:本系列文章主要参考《精通Python设计模式》一书,并且参考一些资料,结合自己的一些看法来总结而来。

  从本篇便开始介绍结构型设计模式,而适配器设计模式便是该类设计模式的一种,那么什么是结构型设计模式呢?

 结构型设计模式:

  其主要用来处理一个系统中不同实体(比如类和对象)之间关系,关注的是提供一种简单的对象组合方式来创造新的功能。

 适配器模式

  该书中介绍主要为了适配器模式主要用于 帮助我们实现两个不兼容接口之间的兼容

  当我们希望把一个老组件用于一个新组系统或者把一个新组件应用于老系统中,同时在代码无法修改的,或者说无法访问这些代码时(在实际开发中,旧系统的代码修改后牵一而动全身,很容易引起系统的崩溃。)。这时候,我们可以编写一个额外的代码层,该代码层包含让这两个接口之间能够通信需要进行的所有修改。

  注:通俗的说就是设计 接口/API,以保证程序符合 开放/封闭 原则,同时保证不修改其他地方接口的调用方式,保持新老代码间的兼容性。

  示例:假设有这样一个场景:

  一、存在一套旧系统,里面包含 Computer类,如下:

class Computer:
def __init__(self, name):
self.name = name def __str__(self):
return 'the {} computer'.format(self.name) def execute(self):
return 'executes a program'

  二、下面有需求,需要为该应用丰富更多的功能,而有了接下来的两个类:Synthesizer、Human如下:

class Synthesizer:
def __init__(self, name):
self.name = name def __str__(self):
return 'the {} synthesizer'.format(self.name) def play(self):
return 'is playing an electronic song' class Human:
def __init__(self, name):
self.name = name def __str__(self):
return '{} the human'.format(self.name) def speak(self):
return 'says hello'

  从上面代码可以看出: Synthesizer 类,主要动作由play()方法执行。Human类主要动作由speak()方法执行。而原来的类 Computer其动作由execute()方法执行。

  并且对于原来的老系统来说,所有动作函数均使用 Obj.execute() 来执行。即对于调用者来说,新系统的组件 Synthesizer.play() 和 Human.speak() 是不存在的,必须像调用 Computer.execute() 一样使用 Synthesizer.execute() 和 Human.execute() 来调用原系统中对象的执行函数。

  而这就是我们所说的常见,在无法修改 旧系统的调用方式和修改其源代码的请求下,为了让新组件去适应(兼容)旧系统的情况。所以这边我们可以使用适配器模式来解决。

  三、于是我们可以创建一个 通用的Adapter类,将一些带不同接口的对象适配到一个统一接口中。

class Adapter:
def __init__(self, obj, adapted_methods):
self.obj = obj
self.__dict__.update(adapted_methods) def __str__(self):
return str(self.obj)

 解析一下:

  这里使用一个__init__魔法方法,将新组件的对象添加obj属性中。而其中在__dict__魔法方法,将新组件对象的方法添加到适配器对象的属性字典中。这样就可以使用适配器对象即可调用新组件的方法。

 

   四、接下来,只需要在调用时,对原有系统的类进行封装,即可实现统一使用 execute() 方法执行动作了。代码如下.

def main():
objects = [Computer('Asus')]
synth = Synthesizer('moog')
objects.append(Adapter(synth, dict(execute=synth.play)))
human = Human('Bob')
objects.append(Adapter(human, dict(execute=human.speak))) for i in objects:
print('{} {}'.format(str(i), i.execute()))
print('type is {}'.format(type(i)))

  注释:其实就是在实例化对象后,使用 Adapter 再将对象包裹一次,最终的调用其实都是调用了 Adapter 类的对象。即:调用适配器对象的execute方法其实就是调用 synth.play或者human.speak方法

  输出结果如下:

the Asus computer executes a program
type is <class '__main__.Computer'>
the moog synthesizer is playing an electronic song
type is <class '__main__.Adapter'>
Bob the human says hello
type is <class '__main__.Adapter'>

  这也是为什么当我们执行下面代码会报错的原因:

for i in objects:
print(i.name)

  当然我们可以这样改:

for i in objects:
print(i.obj.name)

  这样就可以成功了。这是由于 i对象为适配器对象,只是它的属性字典中,execute 其指向的为  Human.speak 的引用地址。故可以直接使用  i.execute() 进行调用。而其属性字典中没有 Human的name属性,当然我们之前 将 human对象传进来了,而其在适配器对象的obj属性指向的是 human对象,故 i.obj.name 即可调用。

  over~~~

浅谈Python设计模式 - 适配器模式的更多相关文章

  1. 浅谈Python设计模式 -- 责任链模式

    声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 之前在最开始就聊了Python设计模式有三种,其中关于创建型和结构型设计模式基本 ...

  2. 浅谈Python设计模式 - 代理模式

    声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 一.在某些应用中,我们想要在访问某个对象之前执行一个或者多个重要的操作,例如,访 ...

  3. 浅谈Python设计模式 - 享元模式

    声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 享元模式: 享元模式是一种用于解决资源和性能压力时会使用到的设计模式,它的核心思 ...

  4. 浅谈Python设计模式 - 外观模式

    声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 外观模式 外观模式的核心在于将复杂的内部实现包装起来,只向外界提供简单的调用接口 ...

  5. 浅谈Python设计模式 - 建造者模式

    声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 建造者模式 当我们想要创建一个由多个部分构成的对象,而且他们的构建需要一步接一步 ...

  6. 浅谈Python设计模式 - 抽象工厂模式

    声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 在上一篇我们对工厂模式中的普通工厂模式有了一定的了解,其实抽象工作就是 表示针对 ...

  7. 浅谈Python设计模式 - 工厂模式

    声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 工厂模式: 顾名思义,工厂则是根据提供的不同的材料,生产出不同的产品.那么在编程 ...

  8. 浅谈Python设计模式 - 原型模式

    声明,本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 在<精通Python设计模式>中把设计模式分为三种类型: 创建型模式 ...

  9. 浅谈Python设计模式 - 单例模式

    本篇主要介绍一下关于Python的单例模式,即让一个类对象有且只有一个实例化对象. 一.使用__new__方法(基类) 要实现单例模式,即为了让一个类只能实例化一个实例,那么我们可以去想:既然限制创建 ...

随机推荐

  1. 洛谷 p1047 校门外的树 线段树做法

    非常easy, 注意一下它是两端开始,也就是说0的位置也有一棵树就好了 我由于太弱了,一道红题交了4,5遍 由于树的砍了就没了,lazy标记最大就是1; 直接贴代码吧 #include<bits ...

  2. wpf, C# 实现目录对话框选择

    引用:using System.Windows.Forms; 代码: FolderBrowserDialog fbWnd = new FolderBrowserDialog(); fbWnd.Desc ...

  3. Docker环境下的前后端分离项目部署与运维(六)搭建MySQL集群

    单节点数据库的弊病 大型互联网程序用户群体庞大,所以架构必须要特殊设计 单节点的数据库无法满足性能上的要求 单节点的数据库没有冗余设计,无法满足高可用 单节点MySQL的性能瓶领颈 2016年春节微信 ...

  4. GPG实践

    遇见的问题 安装之后没有显示如教程中的 直接提示真实姓名于电子邮件的地址 公钥与密钥 设置吊销证书

  5. 20165230田坤烨网络对抗免考报告_基于WIN10的渗透攻击

    目录 简单信息收集 主机发现 ping nmap 端口扫描 nmap OS及服务版本探测 nmap -sV 绕过防火墙尝试 诱饵 随机数据长度 随机顺序扫描目标 MAC地址欺骗 实现win10的渗透攻 ...

  6. c语言之连接符

    c语言之连接符 1.连接符 连接符的概念是结合define预编译指令的使用技巧,用户可以向define中传入字符串来调用不同功能的函数. 2.代码例子 #include <stdio.h> ...

  7. Windows10 下 JAVA JDK版本设置修改操作

    一般情况下,先修改系统环境变量,右键点击桌面上的“此电脑”图标中,选择“属性”,在弹出的属性窗口中选择“高级系统设置”,然后点击“环境变量”     在弹出窗口中的“系统变量”,查到“JAVA_HOM ...

  8. mongo 操作

    1.链接mongo /path_to_mongo/bin/mongo MongoDB shell version: connecting to: test > use logs switched ...

  9. [原创] Agilent 34410A 表与计算机通讯

    1. 接口选择 万用电表出厂时选定为HP-IB接口,应选择为RS-232接口 E:I/O MENU – 2:INTERFACE 选择RS-232 2. 设定波特率 默认9600 E:I/O MENU ...

  10. Sitecore 8.2 工作流程

    假设您的新Sitecore项目的所有开发都已完成.现在的下一步是在网站上填写内容并准备上线.客户通知您他们希望使用专门的网站管理员团队负责整个内容管理流程,并要求您为他们准备实例以便能够执行此操作. ...