写在前面

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

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. 【JUC】2.synchronized

    synchronized关键字的用法也不做太多笔记了,简单回顾一下: synchronized三种使用方式: 修饰实例方法: 线程获取的是当前调用此方法的对象的对象头:即:锁是当前对象: public ...

  2. Android笔记(三) 使得Activity之间可以跳转---Intent

    什么是Intent 一个APP肯定不单单由一个Activity构成,我们在使用过程中,经常需要在多个Activity中跳转,Android中Intent可以帮我们来完成在各个Activity中跳转的功 ...

  3. Linux命令——set 和 unset

    参考:Linux set and unset http://www.runoob.com/linux/linux-comm-set.html https://blog.csdn.net/u010003 ...

  4. scikit-learn中的机器学习算法封装——kNN

    接前面 https://www.cnblogs.com/Liuyt-61/p/11738399.html 回过头来看这张图,什么是机器学习?就是将训练数据集喂给机器学习算法,在上面kNN算法中就是将特 ...

  5. HTTP协议通信原理 与常见报错信息

    HTTP协议通信原理 请求报文 请求行 GET index.html HTTP 1.1 请求方法:get  读取服务器数据内容    post   提交存储服务端数据(用户注册) 协议版本:   ht ...

  6. 《构建之法》第五次作业——Alpha项目测试

    博客开头 这个作业属于哪个课程 https://edu.cnblogs.com/campus/xnsy/2019autumnsystemanalysisanddesign?page=6 这个作业要求在 ...

  7. 滑雪 ( bfs+记忆化

    https://www.luogu.org/problemnew/show/P1434  题目 #include<iostream> #include<cstdio> #inc ...

  8. MyBatis_动态sql_foreach_mysql下foreach批量插入的两种方式

    方法1: 笔记要点出错分析与总结工程组织数据库组织0.重新修改Bean类    修改1.定义接口 //批量插入 public void addEmps(@Param("emps") ...

  9. PHP启动php-fpm成功,但php-cgi进程查找不到 502 getaway

    一般情况大家刚把lnmp环境安装好之后,把nginx中 fastcgi_pass unix:/tmp/php-cgi.sock项修改成 fastcgi_pass 127.0.0.1:9000之后,网页 ...

  10. Python+request 使用pymysql连接数据库mysql的操作,基础篇《十一》

    笔记记录: (1)pymysql中所有的有关更新数据(insert,update,delete)的操作都需要commit,否则无法将数据提交到数据库,既然有了commit(),就一定有对应的rollb ...