声明:本系列文章主要参考《精通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. 使用mxnet实现卷积神经网络LeNet

    1.LeNet模型 LeNet是一个早期用来识别手写数字的卷积神经网络,这个名字来源于LeNet论文的第一作者Yann LeCun.LeNet展示了通过梯度下降训练卷积神经网络可以达到手写数字识别在当 ...

  2. 记录VUE-CLI项目创建及初始化相关

    记录 创建项目 vue init webpack 项目名 配置config下的index.js的文件配置,修改相对路径和配置不打包map文件 修改build-webpack.base.conf.js, ...

  3. 第10组 Alpha事后诸葛亮

    一.组长博客链接 组长博客 二.总结思考 设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 我们的APP主要解决大学生闲置物品处理问题,定义的很清楚,用户 ...

  4. 【BigData】Java基础_ArrayList的使用

    ArrayList概述 ArrayList底层使用的是数组.是List的可变数组实现,这里的可变是针对List而言,而不是底层数组. 数组有自身的特点,不变性,一旦数组被初始化,那么其长度就固定了,不 ...

  5. otl odbc小计

    1. 使用odbc的时候,要注意数据库的编码与odbc配置的编码一致,不然有乱码.所以建议,表中字符编码,数据库的编码,odbc等connector的编码都是utf8,避免乱码问题 2. 安装odbc ...

  6. 【技术博客】Django中文件下载的实现

    开发组在开发过程中,都不可避免地遇到了一些困难或问题,但都最终想出办法克服了.我们认为这样的经验是有必要记录下来的,因此就有了[技术博客]. Django中文件下载的实现 1.背景 在VisualPy ...

  7. pv删除不掉

    [root@master pv]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS ...

  8. pytest新版本(5.3.2)中收集测试方法规则不支持以test结尾的方法

    pytest新版本(5.3.2)中收集测试方法规则不支持以test结尾的方法,只能命名为以test开头,否则不能识别到

  9. 学习Linux要知道的知识点总结

    1 如何查看Linux的user和hostname? (1)打开终端查看 终端左侧的root@zlkj:~$,前面的root为user - 用户名,后面的zlkj为hostname - 主机名. (2 ...

  10. 用idea如何把一个写好的项目传到GitHub上

    原文地址:https://blog.csdn.net/u010775025/article/details/79219491 一.登录到自己的GitHub上,创建一个新的仓库如下图springboot ...