zoukankan      html  css  js  c++  java
  • Python之适配器模式

    一、介绍

    结构型设计模式:主要用来处理一个系统中不同实体之间关系,即将类或者对象组合在一起,重新组成为一种新的、功能更强大的结构。

    1. 类结构型模式:多个类组合而成的系统。
    2. 对象结构型模式:在一个类中定义另外一个类的实例,通过类与对象的组合形成更大的系统,可以通过类中的对象属性去调用这个对象的方法。

    适配器模式:也是属于设计模式中的结构型模式。
      适配器模式主要用于 帮助我们实现两个不兼容接口之间的兼容。

    二、适配器模式

    1、对象结构型适配器示例

    假设存在一套旧的系统ExecuteCmd类,用来执行一些系统命令。

    import subprocess
    
    
    class ExecuteCmd:
        def __init__(self, cmd):
            self.cmd = cmd
    
        def cmd_exe(self):
            result = ""
            result_code = 0
            try:
                result = subprocess.check_output(self.cmd, shell=True)
            except subprocess.CalledProcessError as e:
                result_code = 1
            return result, result_code

    客户端要执行命令的时候,只需要调用这个类的实例方法cmd_exe即可:

    old_obj = ExecuteCmd("ls -l").cmd_exe()

    现在有一个新的系统,仍然是用来执行一些系统命令,但是新的调用方式改变了。

    class NewCmd:
        def __init__(self, cmd):
            self.cmd = cmd
    
        def run_cmd(self):
            result = ""
            result_code = 0
            try:
                result = subprocess.check_output(self.cmd, shell=True)
            except subprocess.CalledProcessError as e:
                result_code = 1
            return result, result_code

    新的调用方式是:

    new_obj = NewCmd("ls -l").run_cmd()

    假设由于新系统支持的命令更多,我们想要把新系统也提供给客户端使用,但是客户端只知道使用某个实例的cmd_exe方法,并不知道新系统的调用方式改变了。

    在不改变新系统NewCmd类的前提下,我们该如何做才能让客户端仍然能正常调用呢?
    此时就需要用到适配器!我们可以创建一个通用的Adapter类,将一些不同接口的对象适配到一个统一接口中。

    在初始化方法init()中,用一个属性obj把我们想要适配的对象保存下来, adapted_methods是一个字典,用于转换接口,key是客户端要调用的方法,value是想要适配的对象真正被调用的方法。

    适配器类定义如下:

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

    使用方法如下

    # 旧接口可以不适配
    old_obj = ExecuteCmd("ls -l").cmd_exe()
    
    # 新接口需要进行适配
    new_obj = NewCmd("ls -l")
    trans_obj = Adapter(new_obj, dict(cmd_exe=new_obj.run_cmd))
    # 适配完成后,就可以跟旧系统一样使用cmd_exe执行命令
    trans_obj.cmd_exe()

    完整的代码展示

    import subprocess
    
    
    class ExecuteCmd:
        def __init__(self, cmd):
            self.cmd = cmd
    
        def cmd_exe(self):
            result = ""
            result_code = 0
            try:
                result = subprocess.check_output(self.cmd, shell=True)
            except subprocess.CalledProcessError as e:
                result_code = 1
            return result, result_code
    
    
    class NewCmd:
        def __init__(self, cmd):
            self.cmd = cmd
    
        def run_cmd(self):
            result = ""
            result_code = 0
            try:
                result = subprocess.check_output(self.cmd, shell=True)
            except subprocess.CalledProcessError as e:
                result_code = 1
            return result, result_code
    
    
    class Adapter:
        def __init__(self, obj, adapted_methods):
            self.obj = obj
            self.__dict__.update(adapted_methods)
    
        def __getattr__(self, item):
            return self.obj.item
    
    
    # 旧接口可以不适配
    old_obj = ExecuteCmd("calc").cmd_exe()
    
    # 新接口需要进行适配
    new_obj = NewCmd("calc")
    # 这里将新系统的run_cmd方法适配成旧系统的cmd_exe方法
    trans_obj = Adapter(new_obj, dict(cmd_exe=new_obj.run_cmd))
    # 适配完成后,就可以跟旧系统一样使用cmd_exe执行命令
    trans_obj.cmd_exe()

    2、类结构型适配器示例

    如果我们希望直接使用一个新的类去适配旧系统的接口时,也可以使用类结构型适配器,方法如下:

    1. 创建一个新的类
    2. 继承需要进行转换的类
    3. 在新的类中实现旧系统的接口
    import subprocess
    
    
    class ExecuteCmd:
        def __init__(self, cmd):
            self.cmd = cmd
    
        def cmd_exe(self):
            result = ""
            result_code = 0
            try:
                result = subprocess.check_output(self.cmd, shell=True)
            except subprocess.CalledProcessError as e:
                result_code = 1
            return result, result_code
    
    
    class NewCmd:
        def __init__(self, cmd):
            self.cmd = cmd
    
        def run_cmd(self):
            result = ""
            result_code = 0
            try:
                result = subprocess.check_output(self.cmd, shell=True)
            except subprocess.CalledProcessError as e:
                result_code = 1
            return result, result_code
    
    
    class Adapter(NewCmd):
        """继承新系统的类"""
    
        def cmd_exe(self):
            """直接在适配器中实现旧系统的接口"""
            return self.run_cmd()
    
    
    # 旧接口
    old_obj = ExecuteCmd("calc").cmd_exe()
    
    # 新接口需要进行适配
    new_obj = Adapter("calc").cmd_exe()
  • 相关阅读:
    jackson 枚举 enum json 解析类型 返回数字 或者自定义文字 How To Serialize Enums as JSON Objects with Jackson
    Antd Pro V5 中ProTable 自定义查询参数和返回值
    ES6/Antd 代码阅读记录
    es 在数据量很大的情况下(数十亿级别)如何提高查询效率啊?
    Antd Hooks
    使用.Net Core开发WPF App系列教程(其它 、保存控件内容为图片)
    使用.Net Core开发WPF App系列教程( 三、与.Net Framework的区别)
    使用.Net Core开发WPF App系列教程( 四、WPF中的XAML)
    使用.Net Core开发WPF App系列教程( 二、在Visual Studio 2019中创建.Net Core WPF工程)
    使用.Net Core开发WPF App系列教程( 一、.Net Core和WPF介绍)
  • 原文地址:https://www.cnblogs.com/Zzbj/p/15778989.html
Copyright © 2011-2022 走看看