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 ...
随机推荐
- Oracle存储过程、函数、包加密wrap
wrap加密可以将PL/SQL的代码实现部分隐藏,提高代码的安全性,如存储过程.函数.包等都隐藏. wrap加密的方法有两种,下面以函数为例分别介绍一下: 方法一: 编写好函数后保存到 d:\test ...
- (备忘)jeecg的$.dialog的一些参数
jeecg表单弹出框采用的技术是lhgdialog 一.配置全局默认参数 (function(config){ config['extendDrag'] = true; // 注意,此配置参数只能在这 ...
- Ansible批量自动化管理工具
一,工具与环境介绍 1.1 ansible简介 批量管理服务器的工具 无需部署agent,通过ssh进行管理 流行的自动化运维工具:https://github.com/ansible/ansible ...
- 运输层3——传输控制协议TCP概述
目录 1. TCP最主要的特点 2. TCP的连接 3. socket在不同场景中的含义 写在前面:本文章是针对<计算机网络第七版>的学习笔记 运输层1--运输层协议概述 运输层2--用户 ...
- Linux网络编程综合运用之MiniFtp实现(九)
上次中实现了FTP命令的映射来避免很多if....else的判断,这次主要是开始实现目录列表的传输,先看一下目前实现的: 数据连接创建好之后则开始进行目录列表的传输了,而要传输目录列表,首先要将目录列 ...
- Vue实现一个图片懒加载插件(转载)
Vue是可以自定义指令的,最近学习过程中遇见了一个需要图片懒加载的功能,最后参考了别人的代码和思路自己重新写了一遍.以下将详细介绍如何实现自定义指令v-lazyload. 先看如何使用这个指令: &l ...
- python 实现定时任务
需求: 想实现 每周一到周五下班钉钉打卡提醒,每周四发周报提醒 使用了二种方法实现 一:apscheduler,代码如下 import json,requests,datetime from apsc ...
- jquery限定文字超出用省略号
都知道用css3可以做到一行超出显示省略号,但多行的用css3很麻烦还要考虑兼容,今天用jquery判断字数来限制出现省略号 $(".ftlt_lt_wzne").each(fun ...
- bzoj 3721: PA2014 Final Bazarek 贪心
如果没有限制,直接取前 $k$ 大即可. 有限制,则只有几种可能:奇换偶,偶换奇. 维护奇数偶数的前缀最小值和后缀最大值即可. code: #include <bits/stdc++.h> ...
- SPOJ 2939 QTREE5 LCT
维护信息的方式十分巧妙~ 维护每一棵 splay 中深度最浅,深度最深的点距离最近的白点. 这样非常方便维护,进行区间合并,进行子树维护 很多时候在维护东西的时候最大/最小/深度最小/深度最大会相对容 ...