浅谈Python设计模式 - 适配器模式
声明:本系列文章主要参考《精通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设计模式 - 适配器模式的更多相关文章
- 浅谈Python设计模式 -- 责任链模式
声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 之前在最开始就聊了Python设计模式有三种,其中关于创建型和结构型设计模式基本 ...
- 浅谈Python设计模式 - 代理模式
声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 一.在某些应用中,我们想要在访问某个对象之前执行一个或者多个重要的操作,例如,访 ...
- 浅谈Python设计模式 - 享元模式
声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 享元模式: 享元模式是一种用于解决资源和性能压力时会使用到的设计模式,它的核心思 ...
- 浅谈Python设计模式 - 外观模式
声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 外观模式 外观模式的核心在于将复杂的内部实现包装起来,只向外界提供简单的调用接口 ...
- 浅谈Python设计模式 - 建造者模式
声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 建造者模式 当我们想要创建一个由多个部分构成的对象,而且他们的构建需要一步接一步 ...
- 浅谈Python设计模式 - 抽象工厂模式
声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 在上一篇我们对工厂模式中的普通工厂模式有了一定的了解,其实抽象工作就是 表示针对 ...
- 浅谈Python设计模式 - 工厂模式
声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 工厂模式: 顾名思义,工厂则是根据提供的不同的材料,生产出不同的产品.那么在编程 ...
- 浅谈Python设计模式 - 原型模式
声明,本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 在<精通Python设计模式>中把设计模式分为三种类型: 创建型模式 ...
- 浅谈Python设计模式 - 单例模式
本篇主要介绍一下关于Python的单例模式,即让一个类对象有且只有一个实例化对象. 一.使用__new__方法(基类) 要实现单例模式,即为了让一个类只能实例化一个实例,那么我们可以去想:既然限制创建 ...
随机推荐
- UNIX网络编程卷1 - >环境搭建(ubuntu16.04)
学习unp网络编程,树上的例子均存在#include“unp.h”,故需要对环境进行配置. 1.到资源页下载www.unpbook.com 2.解压并将unpv13e移动到相应的文件夹下 (因为我 ...
- HTML基础知识---文本编辑练习
飘柔兰花去油洗发水液露去屑止痒控油 阿道夫净屑舒爽清洁头皮去屑洗发水520ml ...
- 基于web公交查询系统---搭建mvc连接数据库(我的毕业设计,进度继续)
建立一个spring的项目:我在已经做过的项目基础下做的,所以接口连接数据库挺快. 搭建好的.对应好数据库: 前几天进度已经完成简单的设计: 完成登录,用户管理(修改删除). 继续的数据库的信息获取, ...
- JVM系列之二:编译过程
1. Java的编译和执行 编译包括两种情况: 1,源码编译成字节码2,字节码编译成本地机器码(符合本地系统专属的指令) 解释执行也包括两种情况: 1,源码解释执行2,字节码解释执行 解释和编译执行的 ...
- Spring Events
https://www.baeldung.com/spring-events by Eugen Paraschiv Spring+ I just announced the new Learn Spr ...
- Solr7.x学习(4)-导入数据
导入配置可参考官网:http://lucene.apache.org/solr/guide,http://lucene.apache.org/solr/guide/7_7/ 1.数据准备(MySQL8 ...
- spark 存取mysql
1.先上代码,存入mysql val spark = SparkSession.builder() .appName("jdbc") .getOrCreate() import s ...
- 解决ios环境下点击输入框页面被顶起不能自动回弹到底部问题
第一步:在标签的输入框中添加获取焦点事件 代码写法: @focus="getFocus" (vue代码) 可直接拷贝拿去放在自己页面元素中,如下: <div class= ...
- Rancher 构建 CI/CD 自动化流程 - 动态配置 Jenkins-slave(一)
一.说明 1)需求: Rancher 上部署 Jenkins-master,服务采用 Jenkins-slave 发布,发布完成后 Jenkins-slave 自动销毁. 2)环境: Rancher ...
- Java的常用API之System类简介
Syetem类 java.lang.System类中提供了大量的静态方法,可以获取与系统相关的信息或系统级操作,在System类的API文档中,常用的方法有: public static long c ...