python 设计模式之访问者模式
写在前面
设计模式是经过总结、优化的,对我们经常会碰到的一些编程问题的可重用解决方案。一个设计模式并不像一个类或一个库那样能够直接作用于我们的代码。反之,设计模式更为高级,它是一种必须在特定情形下实现的一种方法模板。设计模式不会绑定具体的编程语言。一个好的设计模式应该能够用大部分编程语言实现(如果做不到全部的话,具体取决于语言特性)。最为重要的是,设计模式也是一把双刃剑,如果设计模式被用在不恰当的情形下将会造成灾难,进而带来无穷的麻烦。然而如果设计模式在正确的时间被用在正确地地方,它将是你的救星。
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 设计模式之访问者模式的更多相关文章
- 乐在其中设计模式(C#) - 访问者模式(Visitor Pattern)
原文:乐在其中设计模式(C#) - 访问者模式(Visitor Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 访问者模式(Visitor Pattern) 作者:webabc ...
- 折腾Java设计模式之访问者模式
博客原文地址:折腾Java设计模式之访问者模式 访问者模式 Represent an operation to be performed on the elements of an object st ...
- C#设计模式总结 C#设计模式(22)——访问者模式(Vistor Pattern) C#设计模式总结 .NET Core launch.json 简介 利用Bootstrap Paginator插件和knockout.js完成分页功能 图片在线裁剪和图片上传总结 循序渐进学.Net Core Web Api开发系列【2】:利用Swagger调试WebApi
C#设计模式总结 一. 设计原则 使用设计模式的根本原因是适应变化,提高代码复用率,使软件更具有可维护性和可扩展性.并且,在进行设计的时候,也需要遵循以下几个原则:单一职责原则.开放封闭原则.里氏代替 ...
- Python设计模式之MVC模式
# -*- coding: utf-8 -*- # author:baoshan quotes = ('A man is not complete until he is married. Then ...
- 北风设计模式课程---访问者模式(Visitor)
北风设计模式课程---访问者模式(Visitor) 一.总结 一句话总结: 设计模式是日常问题的经验总结方案,所以学好设计模式对日常出现的问题可以有很好的解决. 访问者设计模式有点神似 抽象工厂模式, ...
- python设计模式之模板模式
python设计模式之模板模式 编写优秀代码的一个要素是避免冗余.在面向对象编程中,方法和函数是我们用来避免编写冗余代码的重要工具. 现实中,我们没法始终写出100%通用的代码.许多算法都有一些(但并 ...
- python设计模式之状态模式
python设计模式之状态模式 面向对象编程着力于在对象交互时改变它们的状态.在很多问题中,有限状态机(通常名为状态机)是一个非常方便的状态转换建模(并在必要时以数学方式形式化)工具.首先,什么是状态 ...
- python设计模式之解释器模式
python设计模式之解释器模式 对每个应用来说,至少有以下两种不同的用户分类. [ ] 基本用户:这类用户只希望能够凭直觉使用应用.他们不喜欢花太多时间配置或学习应用的内部.对他们来说,基本的用法就 ...
- python设计模式之命令模式
python设计模式之命令模式 现在多数应用都有撤销操作.虽然难以想象,但在很多年里,任何软件中确实都不存在撤销操作.撤销操作是在1974年引入的,但Fortran和Lisp分别早在1957年和195 ...
随机推荐
- CentOS7安装CDH 第十章:CDH中安装Spark2
相关文章链接 CentOS7安装CDH 第一章:CentOS7系统安装 CentOS7安装CDH 第二章:CentOS7各个软件安装和启动 CentOS7安装CDH 第三章:CDH中的问题和解决方法 ...
- Python标准库3.4.3-webbrowser-21.1
21.1. webbrowser — Convenient Web-browser controller Source code: Lib/webbrowser.py 翻译:Z.F. The web ...
- 关于Django auth注册登录模块的具体使用
from django.urls import path from . import views urlpatterns = [ #主页,用来显示类别等其他数据 path('',views.index ...
- 天兔 -Lepus 慢查询分析平台配置
想要实现慢查询查询分析,需要在被监控端安装percona-toolkit工具. 1.被监控端安装软件包 yum -y install perl-IO-Socket-SSL yum -y insta ...
- 用js刷剑指offer(二叉树中和为某一值的路径)
题目描述 输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径.路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径.(注意: 在返回值的list中,数组长度大 ...
- java.lang.AbstractMethodError: org.powermock.api.mockito.internal.mockmaker.PowerMockMaker.isTypeMockable
[转]https://stackoverflow.com/questions/53539930/java-lang-abstractmethoderror-org-powermock-api-mock ...
- 剑指Offer(三十一):整数中1出现的次数(从1到n整数中1出现的次数)
剑指Offer(三十一):整数中1出现的次数(从1到n整数中1出现的次数) 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https:// ...
- k8s的paas平台
高可靠设计,Etcd 集群,Kubernetes 三主节点,保证集群的高可用性. 基于 GlusterFS /nfs集群,在生产环境和非生产环境下提供存储卷服务. Flannel+VXLAN,提供可靠 ...
- 【动态规划】ZZNU-OJ- 2054 : 油田
2054 : 油田 (一个神奇的功能:点击上方文字进入相应页面) 时间限制:1 Sec 内存限制:32 MiB提交:49 答案正确:6 提交 状态 讨论区 题目描述 在太平洋的一片海域,发现了大量的油 ...
- 0019SpringBoot使用异步任务(多线程)与定时任务
SpringBoot开启异步任务只需要两步配置: 1.在主类上加上注解@EnableAsync开启异步功能 2.在service层的方法上加上注解@Async指定调用方法时是异步的 SpringBoo ...