Python 设计模式行为型访问者模式

目录
  • 一、访问者模式(Visitor Pattern)
  • 二、应用场景
  • 三、代码示例

一、访问者模式(Visitor Pattern)

数据结构中保存着许多元素,当我们希望改变一种对元素的处理方式时,要避免重复的修改数据结构。那么就要求我们在实现代码时,将数据的处理进行分离,即:数据类只提供一个数据处理的接口,而该数据处理接口就被称之为访问者。那么,相同结构的数据面临不同的处理结果时,我们只需要创建不同的访问者。

访问者模式,指作用于一个对象结构体上的元素的操作。访问者可以使用户在不改变该结构体中的类的基础上定义一个新的操作。

优点:

  • 使得在访问者类中针对复杂类结构中的某个类添加新方法较为容易,即:只需要简单地添加一个新的访问者方法即可。如果不采用访问者模式,这需要在每个类中添加一个新的方法。
  • 访问者将相关的方法集中在一个具体的访问者类中,而其他相关的方法集中在另外一个具体的访问者类中。也就是说,访问者子类是按照方法的类型来分类的。

缺点:

  • 增加一个具体的新 ConcreteElement 类比较困难。因为此时需要在每一个 ConcreteVisitor 类中添加该 ConcreteElement 类的访问方法。

二、应用场景

当一个对象的结构中,包含有多种类型的具有不同接口的对象,且用户要在这些对象上进行依赖于具体的类的运算时,需要用到访问者模式。这就是为什么访问者模式要针对每个被访问的子类都设计一个不同的接口的原因。事实上,如果每个被访问的子类都有相同的接口,包括构造方法、其他方法、参数都一致,则访问者类只需要设计一个访问方法,在该方法中含有一个用于区别不同的被访问的子类的参数即可。例如:可以使用被访问者基类作为参数类型。在对象的结构中包含有多种类型的有不同接口的对象时,各个不同的访问方法可能为访问所对应的类提供不同的参数类型。

当有多个不同的并且互不相关的运算将作用到这些对象上,而用户不希望这些运算混淆这些类时,可以使用访问者模式将相关的操作放到独立的类中,例如:为了实现每个结点类中的计算价格方法,可以将所有的计算价格方法放到一个 VisitPrice 类中。

在对象的数据类型很少改变,但是需要经常改变操作或者增加新的操作的情况下,可以使用访问者模式。反之,如果 Element 的子类经常改变结构,例如:需要增加一个新的税种,这就需要在访问者类中增加新的访问方法,因此,在这种情况下使用访问者模式代价较高,尽量不要使用访问者模式。

三、代码示例

该类图包含两个系列的类:“Element 类” 和 “访问者类”,访问者类定义了施加于 Element 类上的操作,为 Element 类提供一些功能。可以有多种具体的访问者类,各自完成特定的目的,如一个访问者类是计算价格,另一个访问者类则是计算存货数量。因此需要定义一个抽象的访问者父类 Visitor 以及用于各种特殊目的具体的子类。Visitor 类必须给每个结点类提供一个操作,即访问方法,例如获得各结点所代表的商品对象的价格等。

实体角色组成:

  • Visitor:为每个 Element 的对象声明一个访问操作。该访问操作的名字最好要包含被访问的类的名字,以便确认该访问操作是专门针对哪个具体的类,如:visitFamilyNoChildren 是专门为了服务类 FamilyNoChildren 的。
  • ConcreteVisitor:实现 Visitor 声明的运算。每个运算实现为对应的类的对象定义的算法的一部分。ConcreteVisitor 提供算法的环境并且存储其局部状态。
  • Element:定义了一些基本的方法,其中包含提供基本数据的方法,例如一些 get()与 set()方法。重要的是,每个 Element 子类都必须定义一个接收者方法,该方法以 Visitor 为参数类型:Accept(Visitor),其作用是为被访问者对象和访问者对象之间的交互提供接口。
  • ConcreteElement:具体的 Element 的子类,例如 ElementA,该类包含一个 accept 方法接收访问者对象。另外,该类还可能定义一些其他的方法以帮助访问者实现一些功能。
  • ObjectStructure:提供一个高层接口,允许访问者访问 Element 的子类。在该类中可以包含一个结构,例如 ArrayList、Vector 等,提供所要访问的 element 的列表。

示例:上市公司的原始财务数据:

  • 对于会计来说需要制作各种报表
  • 对于财务总监来说需要分析公司业绩
  • 对于战略顾问来说需要分析行业变化
class Finance:
    """财务数据结构类"""
    
    def __init__(self):
        self.salesvolume = None          # 销售额
        self.cost = None                 # 成本
        self.history_salesvolume = None  # 历史销售额
        self.history_cost = None         # 历史成本

    def set_salesvolume(self, value):
        self.salesvolume = value

    def set_cost(self, value):
        self.cost = value

    def set_history_salesvolume(self, value):
        self.history_salesvolume = value

    def set_history_cost(self, value):
        self.history_cost = value

    def accept(self, visitor):
        pass

class Finance_year(Finance):
    """2018 年财务数据类"""

    def __init__(self, year):
        Finance.__init__(self)
        self.work = []    # 安排工作人员列表
        self.year = year

    def add_work(self, work):
        self.work.append(work)

    def accept(self):
        for obj in self.work:
            obj.visit(self)

class Accounting:
    """会计类"""

    def __init__(self):
        self.ID = "会计"
        self.Duty = "计算报表"

    def visit(self, table):
        print('会计年度: {}'.format(table.year))
        print("我的身份是: {} 职责: {}".format(self.ID, self.Duty))
        print('本年度纯利润: {}'.format(table.salesvolume - table.cost))
        print('------------------')

class Audit:
    """财务总监类"""

    def __init__(self):
        self.ID = "财务总监"
        self.Duty = "分析业绩"

    def visit(self, table):
        print('会计总监年度: {}'.format(table.year))
        print("我的身份是: {} 职责: {}".format(self.ID, self.Duty))
        if table.salesvolume - table.cost > table.history_salesvolume - table.history_cost:
            msg = "较同期上涨"
        else:
            msg = "较同期下跌"
        print('本年度公司业绩: {}'.format(msg))
        print('------------------')

class Adviser:
    """战略顾问"""
    def __init__(self):
        self.ID = "战略顾问"
        self.Duty = "制定明年战略"

    def visit(self, table):
        print('战略顾问年度: {}'.format(table.year))
        print("我的身份是: {} 职责: {}".format(self.ID, self.Duty))
        if table.salesvolume > table.history_salesvolume:
            msg = "行业上行,扩大生产规模"
        else:
            msg = "行业下行,减小生产规模"
        print('本年度公司业绩: {}'.format(msg))
        print('------------------')

class Work:
    """工作类"""

    def __init__(self):
        self.works = []  # 需要处理的年度数据列表

    def add_work(self, obj):
        self.works.append(obj)

    def remove_work(self, obj):
        self.works.remove(obj)

    def visit(self):
        for obj in self.works:
            obj.accept()

if __name__ == '__main__':
    work = Work()  # 计划安排财务、总监、顾问对2018年数据处理
    # 实例化2018年数据结构
    finance_2018 = Finance_year(2018)
    finance_2018.set_salesvolume(200)
    finance_2018.set_cost(100)
    finance_2018.set_history_salesvolume(180)
    finance_2018.set_history_cost(90)
    accounting = Accounting()   # 实例化会计
    audit = Audit()  # 实例化总监
    adviser = Adviser()     # 实例化顾问
    finance_2018.add_work(accounting)   # 会计安排到2018分析日程中
    finance_2018.add_work(audit)    # 总监安排到2018分析日程中
    finance_2018.add_work(adviser)  # 顾问安排到2018分析日程中
    work.add_work(finance_2018) # 添加2018年财务工作安排
    work.visit()

到此这篇关于Python 设计模式行为型 访问者模式的文章就介绍到这了,更多相关Python访问者模式内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Python实现访问者模式详情

    假设要实现一个存放多种类型数据结构的对象,比如一个存放算术操作数和操作符的树结点,需要存放包含一元操作符.二元操作符和数字类型的结点 class Node:     pass class UnaryOperator(Node):     def __init__(self, operand):         self.operand = operand class BinaryOperator(Node):     def __init__(self, left, right):      

  • 轻松掌握python设计模式之访问者模式

    本文实例为大家分享了python访问者模式代码,供大家参考,具体内容如下 """访问者模式""" class Node(object): pass class A(Node): pass class B(Node): pass class C(A, B): pass class Visitor(object): def visit(self, node, *args, **kwargs): meth = None ""&quo

  • 举例讲解Python设计模式编程中的访问者与观察者模式

    访问者模式 我觉得Visitor模式是在补修改已有程序结构前提下,通过添加额外的访问者完成对代码功能的拓展 为什么这样用?当你的类层次较多,在某层结构中增加新的方法,要是在基类上面添加或者变更,可能破坏原来的设计, 有兼容问题,所以只在需要的类上面动态添加. python的例子 这里是个构建车的例子,每个部件都有一个accept的方法接受我上面说的所谓'访问者',而这个访问者 以参数的方式传进来,但是其实他是一个含有一些功能的类的实例,它拥有很多个visit开头的方法对应不同的部件. 这样就不需

  • Python 如何实现访问者模式

    问题 你要处理由大量不同类型的对象组成的复杂数据结构,每一个对象都需要需要进行不同的处理.比如,遍历一个树形结构,然后根据每个节点的相应状态执行不同的操作. 解决方案 这里遇到的问题在编程领域中是很普遍的,有时候会构建一个由大量不同对象组成的数据结构.假设你要写一个表示数学表达式的程序,那么你可能需要定义如下的类: class Node: pass class UnaryOperator(Node): def __init__(self, operand): self.operand = ope

  • Python 设计模式行为型访问者模式

    目录 一.访问者模式(Visitor Pattern) 二.应用场景 三.代码示例 一.访问者模式(Visitor Pattern) 数据结构中保存着许多元素,当我们希望改变一种对元素的处理方式时,要避免重复的修改数据结构.那么就要求我们在实现代码时,将数据的处理进行分离,即:数据类只提供一个数据处理的接口,而该数据处理接口就被称之为访问者.那么,相同结构的数据面临不同的处理结果时,我们只需要创建不同的访问者. 访问者模式,指作用于一个对象结构体上的元素的操作.访问者可以使用户在不改变该结构体中

  • Python 设计模式行为型解释器模式

    目录 一.解释器模式 二.应用场景 三.代码示例 一.解释器模式 解释器模式,开发者自定义一种 “有内涵” 的语言(或者叫字符串),并设定相关的解释规则,输入该字符串后可以输出公认的解释,或者执行程序可以理解的动作. 优点: 可扩展性比较好,灵活. 增加了新的解释表达式的方式. 易于实现简单文法. 缺点: 可利用场景比较少. 对于复杂的文法比较难维护. 解释器模式会引起类膨胀. 二.应用场景 SQL 解析 符号处理引擎 三.代码示例 实体角色: 终结符表达式:实现与文法中的元素相关联的解释操作,

  • Python设计模式创建型原型模式

    目录 一.原型模式 二.应用场景 三.代码示例 一.原型模式 原型是相对于复制.克隆而言的,但是不同于模板,模板创造出的东西是一模一样,而原型创造出的东西是允许存在差异化和个性化的. 原型模式的实现思路是:“深拷贝” 和 “属性更新”.定义一个原型,设计一个拷贝接口,不需要频繁实例化类,只需要拷贝. 优点: 减少因为对象实例化而产生的损耗,并实行动态装载. 二.应用场景 三.代码示例 要实现多个人的自我介绍,一般方法是每个人都创建一个对象,但是使用原型模式之后,只需要实例化一个对象(标准人),后

  • Python设计模式行为型责任链模式

    目录 一.责任链模式 二.应用场景 三.代码示例 一.责任链模式 责任链模式,将多个处理方法连接成一条链条,请求将在这条链条上流动直到该链条中有一个节点可以处理该请求.通常这条链条是一个对象包含对另一个对象的引用而形成链条,每个节点有对请求的条件,当不满足条件将传递给下一个节点处理. 责任链模式有几个要点: 一个对象中含有另一个对象的引用以此类推形成链条. 每个对象中应该有明确的责任划分,即处理请求的条件. 链条的最后一节应该设计成通用请求处理,以免出现漏洞. 请求应该传入链条的头部 二.应用场

  • C#设计模式之Visitor访问者模式解决长隆欢乐世界问题实例

    本文实例讲述了C#设计模式之Visitor访问者模式解决长隆欢乐世界问题.分享给大家供大家参考,具体如下: 一.理论定义 访问者模式 提供了 一组 集合 对象 统一的 访问接口,适合对 一个集合中的对象,进行逻辑操作,使 数据结构  和 逻辑结构分离. 二.应用举例 需求描述:暑假来啦!三个小伙子组团,开车来 长隆欢乐世界玩. 每个人想玩的项目都不一样, 旅游者 1   想玩:十环过山车,龙卷风暴,梦幻旋马 旅游者 2   想玩:空中警察,欢乐摩天轮,超级水战 旅游者 3   想玩:四维影院,垂

  • python设计模式之抽象工厂模式详解

    抽象工厂模式(Abstract Factory Pattern):属于创建型模式,它提供了一种创建对象的最佳方式.在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类,每个生成的工厂都能按照工厂模式提供对象. 意图: 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 主要解决: 主要解决接口选择的问题. 何时使用: 系统的产品有多于一个的产品族,而系统只消费其中某一族的产品. 如何解决: 在一个产品族里面,定义多个产品. 关键代码: 在一个工厂里聚合多个

  • Java设计模式之java访问者模式详解

    目录 介绍 定义及使用场景 UML类图 角色 财务案例 个人心得体会 静态分派以及动态分派 静态分派 动态分派 访问者模式中的伪动态双分派 对访问者模式的一些思考 总结 优点 缺点 适用性 参考文章 总结 介绍 访问者模式,是行为型设计模式之一 访问者模式是一种将数据操作与数据结构分离的设计模式 访问者模式的基本思想: 软件系统中拥有一个由许多对象构成的.比较稳定的对象结构,这些对象的类都拥有一个 accept 方法用来接受访问者对象的访问 访问者是一个接口,它拥有一个 visit 方法,这个方

  • Python设计模式之职责链模式原理与用法实例分析

    本文实例讲述了Python设计模式之职责链模式原理与用法.分享给大家供大家参考,具体如下: 职责链模式(Chain Of Responsibility):使多个对象都有机会处理请求,从而避免发送者和接收者的耦合关系.将对象连成链并沿着这条链传递请求直到被处理 下面是一个设计模式的demo: #!/usr/bin/env python # -*- coding:utf-8 -*- __author__ = 'Andy' """ 大话设计模式 设计模式--职责链模式 职责链模式(

  • Python设计模式之享元模式原理与用法实例分析

    本文实例讲述了Python设计模式之享元模式原理与用法.分享给大家供大家参考,具体如下: 享元模式(Flyweight Pattern):运用共享技术有效地支持大量细粒度的对象. 下面是一个享元模式的demo: #!/usr/bin/env python # -*- coding:utf-8 -*- __author__ = 'Andy' """ 大话设计模式 设计模式--享元模式 享元模式(Flyweight Pattern):运用共享技术有效地支持大量细粒度的对象 对一个

  • Python设计模式之抽象工厂模式原理与用法详解

    本文实例讲述了Python设计模式之抽象工厂模式原理与用法.分享给大家供大家参考,具体如下: 抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们的类 下面是一个抽象工厂的demo: #!/usr/bin/env python # -*- coding:utf-8 -*- __author__ = 'Andy' """ 大话设计模式 设计模式--抽象工厂模式 抽象工厂模式(Abstract Factory

随机推荐