`
dreamstone
  • 浏览: 289061 次
  • 来自: ...
文章分类
社区版块
存档分类

访问差异类型的集合类--visitor模式入门

阅读更多

访问差异类型的集合类--visitor模式入门
本文对应代码下载这里
一,问题提出
访问同一类型的集合类是我们最常见的事情了,我们工作中这样的代码太常见了。

1 Iterator ie  =  list.iterator();
2 while (ie.hasNext()) {
3     Person p  =  (Person)ie.next();
4     p.doWork();
5 }


这种访问的特点是集合类中的对象是同一类对象Person,他们拥有功能的方法run,我们调用的恰好是这个共同的方法。
在大部份的情况下,这个是可以的,但在一些复杂的情况,如被访问者的继承结构复杂,被访问者的并不是同一类对象,
也就是说不是继承自同一个根类。方法名也并不相同。例如Java GUI中的事件就是一个例子。
例如这样的问题,有如下类和方法:
类:PA ,方法:runPA();
类:PB ,方法:runPB();
类:PC ,方法:runPC();
类:PD ,方法:runPD();
类:PE ,方法:runPE();
有一个集合类List
List list = new ArrayList();
list.add(new PA());
list.add(new PB());
list.add(new PC());
list.add(new PD());
list.add(new PE());
....
二:解决
要求能访问到每个类的对应的方法。我们第一反应应该是这样的。

 1 Iterator ie  =  list.iterator();
 2 while (ie.hasNext()) {
 3     Object obj  =  ie.next();
 4      if  (obj  instanceof  PA) {
 5         ((PA)obj).runPA();
 6     }
else   if (obj  instanceof  PB) {
 7         ((PB)obj).runPB();
 8     }
else   if (obj  instanceof  PC) {
 9         ((PC)obj).runPC();
10     }
else   if (obj  instanceof  PD) {
11         ((PD)obj).runPD();
12     }
else   if (obj  instanceof  PE) {
13         ((PE)obj).runPE();
14     }

15 }


三:新问题及分析解决
当数目变多的时候,维护if else是个费力气的事情:
仔细分析if,else做的工作,首先判断类型,然後根据类型执行相应的函数
如何才能解决这两个问题呢?首先想到的是java的多态,多态就是根据参数执行相应的内容,
能很容易的解决第二个问题,我们可以写这样一个类:

 1 public   class  visitor {
 2      public   void  run(PA pa) {
 3         pa.runPA();
 4     }

 5      public   void  run(PB pb) {
 6         pb.runPB();
 7     }

 8      public   void  run(PC pc) {
 9         pc.runPC();
10     }

11      public   void  run(PD pd) {
12         pd.runPD();
13     }

14      public   void  run(PE pe) {
15         pe.runPE();
16     }

17 }


这样只要调用run方法,传入对应的参数就能执行了。
还有一个问题就是判断类型。由于重载(overloading)是静态多分配(java语言本身是支持"静态多分配"的。
关于这个概念请看这里)所以造成重载只根据传入对象的定义类型,而不是实际的类型,所以必须在传入前就确定类型,
这可是个难的问题,因为在容器中对象全是Object,出来后要是判断是什么类型必须用
if (xx instanceof xxx)这种方法,如果用这种方法启不是又回到了原点,有没有什么更好的办法呢?

我们知到Java还有另外一个特点,覆写(overriding),而覆写是"动态单分配"的(关于这个概念见这里),
那如何利用这个来实现呢?看下边这个方法:
 我们让上边的一些类PA PB PC PD PE都实现一个接口P,加入一个方法,accept();

 1 public   void  accept(visitor v) {
 2      // 把自己传入1
 3     v.run( this );
 4 }

 5 然後在visitor中加入一个方法
 6 public   void  run(P p) {
 7      // 把自己传入2
 8     p.accept( this );
 9 }

10 // 这样你在遍历中可以这样写
11 Visitor v  =   new  Visitor();
12 Iterator ie  =  list.iterator();
13 while (ie.hasNext()) {
14     P p  =  (P)ie.next();
15         p.accept(v);
16     }

17 }


首先执行的是"把自己传入2",在这里由于Java的特性,实际执行的是子类的accept(),也就是实际类的accept
然後是"把自己传入1",在这里再次把this传入,就明确类型,ok我们巧妙的利用overriding解决了这个问题
其实归纳一下第二部分,一个关键点是"自己认识自己",是不是很可笑。
其实在计算计技术领域的很多技术上看起来很高深的东西,其实就是现有社会中人的生活方式的一种映射
而且这种方式是简单的不能再简单的方式。上边的全部过程基本上是一个简单的visitor模式实现,visitor模式
已经是设计模式中比较复杂的模式了,但其实原理简单到你想笑。看看下边这个比喻也许你的理解会更深刻。

四:一个帮助理解的比喻:
题目:指挥工人工作
条件:你有10个全能工人,10样相同工作。
需求:做完工作
实现:大喊一声所有人去工作

条件变了,工人不是全能,但是工作相同,ok问题不大
条件再变,工作不是相同,但工人是全能,ok问题不大

以上三种情况在现实生活中是很少发生得,最多的情况是这样:
10个工人,每人会做一种工作,10样工作。你又一份名单Collection)写着谁做什么。但你不认识任何人
这个时候你怎么指挥呢,方案一:
你可以一个个的叫工人,然後问他们名字,认识他们,查名单,告诉他们做什么工作。
你可以直接叫出他们名字,告诉他们干什么,不需要知到他是谁。
看起来很简单。但如果你要指挥10万人呢 ?而且人员是流动的,每天的人不同,你每天拿到一张文档。
其实很简单,最常用的做法是,你把这份名单贴在墙上,然後大喊一声,所有人按照去看,按照自己的分配情况去做。
这里利用的关键点是"所有工人自己认识自己",你不能苛求每个工人会做所有工作,不能苛求所有工作相同,但你
能要求所有工人都认识自己。

再想想我们开始的程序,每个工人对应着PA PB PC PD PE....
所有的工人都使工人P
每个工人会做的东西不一样runPA runPB runPC
你有一份名单Visitor(重载)记录着谁做什么工作。

看完上边这些,你是不是会产生如下的问题:
问题:为什么不把这些方法的方法名做成一样的,那就可以解决了。
例如,我们每个PA ,PB ,PC都加入一个run 方法,然後run内部再调用自己对应的runPx()方法。
答案:有些时候从不同的角度考虑,或者因为实现的复杂度早成很难统一方法名。
例如上边指挥人工作的例子的例子,其实run方法就是大叫一声去工作,因为每个工人只会做一种工作,所以能行
但我们不能要求所有人只能会做一种事情,这个要求很愚蠢。所以如果每个工人会干两种或者多种工作呢,
也就是我PA 有runPA() walkPA()等等方法, PB有runPB() climbPB()等等。。。
这个时候按照名单做事才是最好的办法。

五:作者的话
所以说模式中很多复杂的东西,在现实中其实是很基本的东西,多多代入代出能帮助理解模式。

看完本文,如果你对visitor模式有更多的兴趣,想了解更多请看如下几篇文章。
1,静态分派,动态分派,多分派,单分派 --------------   visitor模式准备
2,访问差异类型的集合类 ------------------------   visitor模式入门(本文)
3,visitor模式理论及学术概念-------------------   visitor模式深入
4,重载overloading和覆写overriding哪个更早执行--   visitor帮助篇
虽然排列顺序是1,2,3,4 但是我个人建议的学习方式是2,1,3,4因为这个顺序更方便一般人理解

 

 

 

 

 

 

 

 

 

 


 

分享到:
评论

相关推荐

    设计模式C++学习之访问者模式(Visitor)

    访问者模式(Visitor)是一种行为设计模式,它允许在不修改对象结构的前提下向对象结构中的元素添加新的操作。这种模式将算法与数据结构分离,使得算法可以独立于数据结构进行变化,增强了系统的可扩展性。 在C++中...

    decaf-lang#decaf-book-spec#visitor模式1

    rust中当然也可以有visitor模式这样的东西,比如

    设计模式-访问者(Visitor)模式详解和应用.pdf

    访问者模式(Visitor Pattern)是一种行为型设计模式,它允许我们向一组已存在的类添加新的行为,而无需修改这些类。这种模式的核心思想是在不改变元素类的前提下,通过引入新的访问者来扩展系统的功能。 #### 二、...

    设计模式之访问者模式(Visitor)

    **访问者模式(Visitor)详解** 访问者模式是一种行为设计模式,它使你可以在不修改对象结构的情况下,为对象添加新的操作。这种模式的核心在于将数据结构与对这些数据的操作解耦,使得增加新的操作变得容易,同时...

    C#面向对象设计模式纵横谈(24):(行为型模式) Visitor 访问者模式

    ### C#面向对象设计模式纵横谈(24):(行为型模式) Visitor 访问者模式 #### 概述 在本篇文章中,我们将深入探讨面向对象设计模式中的一个非常重要的模式——**Visitor(访问者)模式**。此模式属于行为型模式的一...

    Visitor模式

    5. **对象结构(Object Structure)**:可以遍历其元素并可以提供访问者访问其元素的接口,通常是一个集合类或者提供迭代器。 **模式的优点:** - **封装性**:访问者模式将对对象结构的操作封装在访问者中,使得...

    设计模式-访问者模式(Visitor)

    访问者模式(Visitor)是一种行为设计模式,它允许在不修改对象结构的前提下向对象结构中的元素添加新的操作。这种模式的核心思想是分离了算法和对象结构,使得算法可以在不改变对象结构的情况下独立变化。 访问者...

    基于visitor模式和访问者模式的表达式树_求值引擎

    一个`Expression`接口或类定义了接受访问者的操作,而每个具体的表达式节点类(如加法、减法、乘法、除法等)实现这个接口,接受并处理特定类型的访问者。访问者类(如`Evaluator`)则包含了实际的求值逻辑,它可以...

    C++ Visitor模式

    Visitor模式是设计模式中的一种行为模式,它在对象结构中引入了一个访问者角色,使得访问者能够对结构中的每个元素进行操作,而不改变元素本身的行为。这种模式允许我们在不修改已有类的情况下增加新的操作,遵循了...

    设计模式精解-GoF-23种设计模式解析--附C++源代码

    - 访问者模式(Visitor):表示一个作用于某对象结构中的各元素的操作,它可以在不改变各元素的类的前提下定义作用于这些元素的新操作。 在C++中,这些设计模式通常通过面向对象的特性,如继承、封装和多态来实现...

    设计模式系列之visitor

    "设计模式系列之visitor"是一个关于软件设计模式的讨论,特别是关注于“访问者”(Visitor)模式。这个模式是GOF(Gamma, Helm, Johnson, Vlissides)在他们的经典著作《设计模式:可复用面向对象软件的基础》中提出...

    这是一套 Java 设计模式的集合示例-design-pattern.zip

    - 访问者模式(Visitor):表示一个作用于某对象结构中的各元素的操作,它可以在不改变各元素的类的前提下定义作用于这些元素的新操作。 在"design-pattern-master"中,你可以期待找到各种设计模式的具体实现,每...

    访问者模式VisitorPattern

    **访问者模式(VisitorPattern)** 访问者模式是一种行为设计模式,它使你能在不修改对象结构的前提下向对象添加新的操作。这种模式常用于处理具有复杂逻辑的对象结构,特别是当你需要对这些对象进行多态操作时。访问...

    c++设计模式-行为型模式-访问者模式

    访问者(Visitor)模式的定义:将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,为数据结构中的每个元素提供多种访问方式。...

    设计模式 - 访问者模式

    访问者模式(Visitor Pattern)是一种行为设计模式,它使你能在不修改对象结构的前提下向其添加新的操作。这种模式常用于处理具有相同接口或抽象类的对象结构,使得可以在不改变原有结构的基础上增加功能,实现对...

    设计模式精解-GoF 23种设计模式解析附C++.pdf

    - **Singleton模式**:确保一个类只有一个实例,并提供一个全局访问点。 - **Builder模式**:将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。 - **Prototype模式**:通过克隆已有的实例...

    设计模式之访问者模式(Visitor Pattern)

    **访问者模式(Visitor Pattern)**是一种行为设计模式,它提供了一种在不修改对象结构的情况下增加新操作的方法。这种模式的主要思想是将数据结构与算法分离,使得算法可以在不改变对象结构的情况下独立变化。 在...

    Recruit-Restaurant-Visitor-Forecasting-master.zip

    《Recruit Restaurant Visitor Forecasting: 使用Jupyter Notebook进行数据分析与预测》 在现代商业环境中,数据分析和预测已经成为餐厅管理中的重要工具。"Recruit Restaurant Visitor Forecasting-master.zip" 是...

    online-books#dt-fe-weekly#189.精读《设计模式 - Visitor 访问者模式》1

    可以看到,要实现操作权转让到 Visitor,核心是元素必须实现一个 Accept 函数,将这个对象抛给 Visitor:从上面代码可以看出这样一条链路:Ele

    plugins-file-visitor:通过插件迭代文件的实用程序类

    在`plugins-file-visitor-master`这个压缩包中,我们可以期待找到以下内容: - `src/main/java`目录:包含`plugins-file-visitor`库的源代码,可能有`Visitor`、`Filter`等关键类的实现。 - `src/test/java`目录:...

Global site tag (gtag.js) - Google Analytics