写在前面

设计模式是经过总结、优化的,对我们经常会碰到的一些编程问题的可重用解决方案。一个设计模式并不像一个类或一个库那样能够直接作用于我们的代码。反之,设计模式更为高级,它是一种必须在特定情形下实现的一种方法模板。设计模式不会绑定具体的编程语言。一个好的设计模式应该能够用大部分编程语言实现(如果做不到全部的话,具体取决于语言特性)。最为重要的是,设计模式也是一把双刃剑,如果设计模式被用在不恰当的情形下将会造成灾难,进而带来无穷的麻烦。然而如果设计模式在正确的时间被用在正确地地方,它将是你的救星。

1。为什么要使用设计模式?

从理论上来说,设计模式是对程序问题比较好的解决方案。无数的程序员都曾经遇到过这些问题,并且他们使用这些解决方案去处理这些问题。所以当你遇到同样的问题,为什么要去想着创建一个解决方案而不是用现成的并且被证明是有效的呢?

2。访问者模式解决了什么问题?

1)对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。  
2)需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作”污染”这些对象的类,也不希望在增加新操作时修改这些类。

3。访问者模式使用场景

1)对象结构比较稳定,但经常需要在此对象结构上定义新的操作

2)需要对一个对象结构中的对象进行很多不同的且不相关的操作,而需要避免这些操作“污染”这些对象的类,也不希望在增加新操作时修改这些类。

比如:访问者可以对功能进行统一,可以做报表、UI、拦截器与过滤器。

数据类只提供一个数据处理的接口,而数据类的处理方法我们叫它访问者

下面例子可以实现:安排不同年份的财务报表给不同的角色分析,这就是访问者模式的魅力;访问者模式的核心是在保持原有数据结构的基础上,实现多种数据的处理方法,该方法的角色就是访问者。

4。访问者模式优点

1)使得数据结构和作用于结构上的操作解耦,使得操作集合可以独立变化。

2)添加新的操作或者说访问者会非常容易。

3)将对各个元素的一组操作集中在一个访问者类当中。

4)使得类层次结构不改变的情况下,可以针对各个层次做出不同的操作,而不影响类层次结构的完整性。

5)可以跨越类层次结构,访问不同层次的元素类,做出相应的操作。
6)如果操作的逻辑改变,我们只需要改变访问者的实现就够了,而不用去修改其他所有的商品类。

7)添加新类别的商品到系统变得容易。只需要改变一下访问者接口以及其实现。已经存在的商品类别不会被干扰影响。

5。访问者模式缺点

1)增加新的元素会非常困难。

2)实现起来比较复杂,会增加系统的复杂性。

3)破坏封装,如果将访问行为放在各个元素中,则可以不暴露元素的内部结构和状态,但使用访问者模式的时候,为了让访问者能获取到所关心的信息,元素类不得不暴露出一些内部的状态和结构,就像收入和支出类必须提供访问金额和单子的项目的方法一样。

4)visit()方法的返回值的类型在设计系统式就需要明确。不然,就需要修改访问者的接口以及所有接口实现。另外如果访问者接口的实现太多,系统的扩展性就会下降。

6。举个例子来访问者模式

例子我也是拿了别人的,我做了一些小修改。变了些参数变量名。这个例子执行访问的类 AnalyseData也可以不要的。

#data   base class
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 #2018年的财务情况
class Finance_year(Finance):
def __init__(self,year):
Finance.__init__(self)
self.analyst=[]
self.year=year def add_analyst(self,worker): #有哪些分析师来分析数据
self.analyst.append(worker) def accept(self): #分析师列表里面的人去分析数据
for v in self.analyst:
v.visit(self) #会计
class Accounting:
def __init__(self):
self.id='会计'
self.Duty='计算报表' def visit(self,year_data):
print('我现在分析的是{}年的数据'.format(year_data.year))
print('我的身份是:{},职责:'.format(self.id,self.Duty))
print('本年度纯利润:{}'.format(year_data.salesvolume-year_data.cost))
print('---------------------------------------') #财务总监
class Audit:
def __init__(self):
self.id='财务总监'
self.Duty='分析业绩' def visit(self,year_data): #要把具体哪一年的数据传给分析师,让分析师去分析
print('我现在分析的是{}年的数据'.format(year_data.year))
print('我的身份是:{},职责:'.format(self.id,self.Duty))
if year_data.salesvolume-year_data.cost > year_data.history_salesvolume - year_data.history_cost:
msg='较同期上涨'
else:
msg='较同期下跌'
print('本年度公司业绩:{}'.format(msg))
print('---------------------------------') #战略顾问
class Advisor:
def __init__(self):
self.id='战略顾问'
self.Duty='制定明年策略' def visit(self,year_data):
print('我现在分析的是{}年的数据'.format(year_data.year))
print('我的身份是:{},职责:'.format(self.id,self.Duty))
if year_data.salesvolume > year_data.history_salesvolume:
msg='行业上涨,扩大规模'
else:
msg='行业下跌,减少规模'
print('本年度公司业绩:{}'.format(msg))
print('------------------------------') #执行分析
class AnalyseData:
def __init__(self):
self.datalist=[] #需要处理的数据列表, def add_data(self,year_data):
self.datalist.append(year_data) def remove_data(self,year_data):
self.datalist.remove(year_data) def visit(self):
for d in self.datalist:
d.accept() if __name__=='__main__':
w=AnalyseData() #计划安排财务,总监,顾问对2018年数据处理
finance_2018=Finance_year(2018) #2018年的财务数据
finance_2018.set_salesvolume(200)
finance_2018.set_cost(90)
finance_2018.set_history_salesvolume(190)
finance_2018.set_history_cost(80) accounting=Accounting()
audit=Audit()
advisor=Advisor() finance_2018.add_analyst(accounting) #会计参与2018年的数据分析,然后执行了自己的visit方法
finance_2018.add_analyst(audit)
finance_2018.add_analyst(advisor) #finance_2018.accept() #也可以直接这样调用
w.add_data(finance_2018)
w.visit()

参考

https://yq.aliyun.com/articles/694041

https://www.cnblogs.com/xiaozhiqi/p/5778865.html

https://www.lmlphp.com/user/56/article/item/12041/

https://blog.csdn.net/a910626/article/details/50766033

python 设计模式之访问者模式的更多相关文章

  1. 乐在其中设计模式(C#) - 访问者模式(Visitor Pattern)

    原文:乐在其中设计模式(C#) - 访问者模式(Visitor Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 访问者模式(Visitor Pattern) 作者:webabc ...

  2. 折腾Java设计模式之访问者模式

    博客原文地址:折腾Java设计模式之访问者模式 访问者模式 Represent an operation to be performed on the elements of an object st ...

  3. C#设计模式总结 C#设计模式(22)——访问者模式(Vistor Pattern) C#设计模式总结 .NET Core launch.json 简介 利用Bootstrap Paginator插件和knockout.js完成分页功能 图片在线裁剪和图片上传总结 循序渐进学.Net Core Web Api开发系列【2】:利用Swagger调试WebApi

    C#设计模式总结 一. 设计原则 使用设计模式的根本原因是适应变化,提高代码复用率,使软件更具有可维护性和可扩展性.并且,在进行设计的时候,也需要遵循以下几个原则:单一职责原则.开放封闭原则.里氏代替 ...

  4. Python设计模式之MVC模式

    # -*- coding: utf-8 -*- # author:baoshan quotes = ('A man is not complete until he is married. Then ...

  5. 北风设计模式课程---访问者模式(Visitor)

    北风设计模式课程---访问者模式(Visitor) 一.总结 一句话总结: 设计模式是日常问题的经验总结方案,所以学好设计模式对日常出现的问题可以有很好的解决. 访问者设计模式有点神似 抽象工厂模式, ...

  6. python设计模式之模板模式

    python设计模式之模板模式 编写优秀代码的一个要素是避免冗余.在面向对象编程中,方法和函数是我们用来避免编写冗余代码的重要工具. 现实中,我们没法始终写出100%通用的代码.许多算法都有一些(但并 ...

  7. python设计模式之状态模式

    python设计模式之状态模式 面向对象编程着力于在对象交互时改变它们的状态.在很多问题中,有限状态机(通常名为状态机)是一个非常方便的状态转换建模(并在必要时以数学方式形式化)工具.首先,什么是状态 ...

  8. python设计模式之解释器模式

    python设计模式之解释器模式 对每个应用来说,至少有以下两种不同的用户分类. [ ] 基本用户:这类用户只希望能够凭直觉使用应用.他们不喜欢花太多时间配置或学习应用的内部.对他们来说,基本的用法就 ...

  9. python设计模式之命令模式

    python设计模式之命令模式 现在多数应用都有撤销操作.虽然难以想象,但在很多年里,任何软件中确实都不存在撤销操作.撤销操作是在1974年引入的,但Fortran和Lisp分别早在1957年和195 ...

随机推荐

  1. 在使用pandas获取网上数据报出url错误的解决办法

    在使用pandas.read_csv('网址名')时,出现url错误是,需要在导包出添加一下两句代码 import ssl ssl._create_default_https_context = ss ...

  2. 记录java+testng运行selenium(二)---定义元素类及浏览器

    一: 元素类 整体思路: 1. 根据状态可分可见和不可见两种 2. 同一个路径可以查找单个元素或多个元素 3. 获取元素text或者指定的value值 4. selenium对元素操作有两种,一是通过 ...

  3. Python函数式编程-map/reduce

    1.map map()传入的第一个参数是f,即函数对象本身. map()函数接收两个参数,一个是函数,一个是Interable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterat ...

  4. 实战jvisualvm

    在上一次[https://www.cnblogs.com/webor2006/p/10629889.html]已经编写了一个能在堆空间出现内存溢出的代码,先来回顾一下: 其中咱们给JVM配置了如下参数 ...

  5. evpp 上传文件问题转

    背景 因为项目需求,需要使用360的evpp库,来实现一个接口,支持文件上传. 实际操作过程中,发现了一些问题,记录下来. 前端文件上传方式 简单的使用input标签 <body> < ...

  6. NodeJS开发博客(二) 接入数据库

    1. mysql 数据库下载网址:https://dev.mysql.com/downloads/mysql/ 账号是 root 密码是 a1************ 网站账号是邮箱,密码是 Aa1* ...

  7. ARP详解

    1.学习ARP前要了解的内容 建立TCP连接与ARP的关系 应用接受用户提交的数据,触发TCP建立连接,TCP的第一个SYN报文通过connect函数到达IP层,IP层通过查询路由表: 如果目的IP和 ...

  8. Django rest framework的基本用法

    今天在网上看到几篇比较不错的drf基本功能介绍,本来想自己写一篇,后来发现脱不开原作者的思路,遂卒,直接扔链接小伙伴自己去看吧.... 1.django rest framework apiview. ...

  9. MySQL 表之间的关系

    表之间的关系 # 定义一张部门员工表 emp id name gander dep_name dep_desc 1 ming male 教学部 教书 2 lilei male 教学部 教书 3 ham ...

  10. [SDOI2015][bzoj 3994][Luogu P3327] 约数个数和 (莫比乌斯反演)

    题目描述 设d(x)d(x)d(x)为xxx的约数个数,给定NNN.MMM,求 ∑i=1N∑j=1Md(ij)\sum^{N}_{i=1}\sum^{M}_{j=1} d(ij)i=1∑N​j=1∑M ...