声明:本系列文章主要参考《精通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. P1553 数字反转(升级版)

    Emma,关于这道题,我..不想说啥子,也就做了它一个下午左右吧(原由:本人太菜) 补充一个知识点goto语句: 这个东西特别的好用,可以直接无条件调到冒号后面的语句,进行操作. 举个例子: #inc ...

  2. Eclipse对spring-boot,spring-boot-mybatis的搭建

    1.准备工作 1.1.如果没有sts(spring tool suite)插件,  则需要下载. 1.1.1.eclipse下载的话,一定要注意版本,因为eclipse会直接下载最新版本,如果ts版本 ...

  3. ibatis实现分页查询

    最近在做老项目改造,分享一个之前写的ibatis(这里特指ibatis2.x的版本)分页插件. 大致原理就是通过重写SqlExecutor的executeQuery方法,实现分页查询,支持mysql和 ...

  4. cocos:C++ 导出到lua, cocos2dx_extension.ini修改

    cocos:C++ 导出到lua, cocos2dx_extension.ini修改 [zq] //zq section, 需要和genbindings.py中的配置相同 # the prefix t ...

  5. Mysql 查看连接数,状态 最大并发数,以及设置连接数

    show variables like '%max_connections%'; 查看最大连接数 set global max_connections=1000  重新设置最大连接数 set-vari ...

  6. java 查找指定包下的类

    package com.jason.test; import java.io.File; import java.io.IOException; import java.io.UnsupportedE ...

  7. ThreadPoolExecutor源码2

    public class ThreadPoolExecutor1 extends AbstractExecutorService1 { // 11100000000000000000000000000 ...

  8. Apache Kafka使用默认配置执行一些负载测试来完成性能测试和基准测试

    Kafka是一种分布式,分区,复制的提交日志服务.它提供了消息传递系统的功能.   我们先来看看它的消息传递术语: Kafka在称为主题的类别中维护消息的提要. 我们将调用向Kafka主题生成器发布消 ...

  9. Python基础笔记(五)

    1. 类(class) 下面的代码建立了一个Employee类: #!/usr/bin/env python3 # -*- coding: utf-8 -*- class Employee(objec ...

  10. c# mvc webapi的put报405错误

    程序在本机调试可正常修改,本机是iis11 放到服务器上,报错了:405.服务器iis7.0 返回的错误页面: <!DOCTYPE html PUBLIC "-//W3C//DTD X ...