本文翻译自:When should I use the Visitor Design Pattern? [closed]

I keep seeing references to the visitor pattern in blogs but I've got to admit, I just don't get it. 我一直在博客中看到对访客模式的引用,但我必须承认,我只是不明白。 I read the wikipedia article for the pattern and I understand its mechanics but I'm still confused as to when I'd use it. 我阅读了维基百科文章的模式 ,我理解它的机制,但我仍然对我何时使用它感到困惑。

As someone who just recently really got the decorator pattern and is now seeing uses for it absolutely everywhere I'd like to be able to really understand intuitively this seemingly handy pattern as well. 作为最近刚刚获得装饰模式的人,现在看到它在任何地方的用途我都希望能够直观地理解这个看似方便的模式。


#1楼

参考:https://stackoom.com/question/14OM/我什么时候应该使用访客设计模式-关闭


#2楼

In my opinion, the amount of work to add a new operation is more or less the same using Visitor Pattern or direct modification of each element structure. 在我看来,使用Visitor Pattern或直接修改每个元素结构,添加新操作的工作量大致相同。 Also, if I were to add new element class, say Cow , the Operation interface will be affected and this propagates to all existing class of elements, therefore requiring recompilation of all element classes. 另外,如果我要添加新的元素类,比如说Cow ,那么Operation接口将受到影响,并且会传播到所有现有的元素类,因此需要重新编译所有元素类。 So what is the point? 那有什么意义呢?


#3楼

Visitor Pattern as the same underground implementation to Aspect Object programming.. Visitor Pattern作为Aspect对象编程的相同地下实现..

For example if you define a new operation without changing the classes of the elements on which it operates 例如,如果您定义新操作而不更改其操作的元素的类


#4楼

There are at least three very good reasons for using the Visitor Pattern: 使用访客模式至少有三个非常好的理由:

  1. Reduce proliferation of code which is only slightly different when data structures change. 减少代码的扩散,这在数据结构发生变化时略有不同。

  2. Apply the same computation to several data structures, without changing the code which implements the computation. 将相同的计算应用于多个数据结构,而不更改实现计算的代码。

  3. Add information to legacy libraries without changing the legacy code. 在不更改旧代码的情况下将信息添加到旧库。

Please have a look at an article I've written about this . 请看一篇我写的关于此的文章 。


#5楼

While I have understood the how and when, I have never understood the why. 虽然我已经理解了如何以及何时,但我从未理解为什么。 In case it helps anyone with a background in a language like C++, you want to read this very carefully. 如果它能帮助任何具有C ++语言背景的人,你想要仔细阅读 。

For the lazy, we use the visitor pattern because "while virtual functions are dispatched dynamically in C++, function overloading is done statically" . 对于懒惰,我们使用访问者模式,因为“当在C ++中动态调度虚函数时,函数重载是静态完成的” 。

Or, put another way, to make sure that CollideWith(ApolloSpacecraft&) is called when you pass in a SpaceShip reference that is actually bound to an ApolloSpacecraft object. 或者,换句话说,确保在传入实际绑定到ApolloSpacecraft对象的SpaceShip引用时调用CollideWith(ApolloSpacecraft&)。

class SpaceShip {};
class ApolloSpacecraft : public SpaceShip {};
class ExplodingAsteroid : public Asteroid {
public:virtual void CollideWith(SpaceShip&) {cout << "ExplodingAsteroid hit a SpaceShip" << endl;}virtual void CollideWith(ApolloSpacecraft&) {cout << "ExplodingAsteroid hit an ApolloSpacecraft" << endl;}
}

#6楼

I found it easier in following links: 我发现以下链接更容易:

In http://www.remondo.net/visitor-pattern-example-csharp/ I found an example that shows an mock example that shows what is benefit of visitor pattern. 在http://www.remondo.net/visitor-pattern-example-csharp/中,我找到了一个示例,其中显示了一个模拟示例,显示了访问者模式的好处。 Here you have different container classes for Pill : 这里你有不同的Pill容器类:

namespace DesignPatterns
{public class BlisterPack{// Pairs so x2public int TabletPairs { get; set; }}public class Bottle{// Unsignedpublic uint Items { get; set; }}public class Jar{// Signedpublic int Pieces { get; set; }}
}

As you see in above, You BilsterPack contain pairs of Pills' so you need to multiply number of pair's by 2. Also you may notice that Bottle use unit which is different datatype and need to be cast. 正如您在上面看到的,You BilsterPack包含成对的Pills'因此您需要BilsterPack数量乘以2.此外,您可能会注意到Bottle使用的unit是不同的数据类型,需要进行投射。

So in main method you may calculate pill count using following code: 因此,在主要方法中,您可以使用以下代码计算药丸计数:

foreach (var item in packageList)
{if (item.GetType() == typeof (BlisterPack)){pillCount += ((BlisterPack) item).TabletPairs * 2;}else if (item.GetType() == typeof (Bottle)){pillCount += (int) ((Bottle) item).Items;}else if (item.GetType() == typeof (Jar)){pillCount += ((Jar) item).Pieces;}
}

Notice that above code violate Single Responsibility Principle . 请注意,上述代码违反了Single Responsibility Principle That means you must change main method code if you add new type of container. 这意味着如果添加新类型的容器,则必须更改主方法代码。 Also making switch longer is bad practice. 使开关更长是不好的做法。

So by introducing following code: 因此,通过引入以下代码:

public class PillCountVisitor : IVisitor
{public int Count { get; private set; }#region IVisitor Memberspublic void Visit(BlisterPack blisterPack){Count += blisterPack.TabletPairs * 2;}public void Visit(Bottle bottle){Count += (int)bottle.Items;}public void Visit(Jar jar){Count += jar.Pieces;}#endregion
}

You moved responsibility of counting number of Pill s to class called PillCountVisitor (And we removed switch case statement). 您将计数Pill的数量的责任转移到了名为PillCountVisitor类(并且我们删除了switch case语句)。 That mean's whenever you need to add new type of pill container you should change only PillCountVisitor class. 这意味着每当你需要添加新类型的药丸容器时,你应该只改变PillCountVisitor类。 Also notice IVisitor interface is general for using in another scenarios. 另请注意, IVisitor接口通常用于其他方案。

By adding Accept method to pill container class: 通过将Accept方法添加到药丸容器类:

public class BlisterPack : IAcceptor
{public int TabletPairs { get; set; }#region IAcceptor Memberspublic void Accept(IVisitor visitor){visitor.Visit(this);}#endregion
}

we allow visitor to visit pill container classes. 我们允许访客参观药丸容器类。

At the end we calculate pill count using following code: 最后,我们使用以下代码计算药丸计数:

var visitor = new PillCountVisitor();foreach (IAcceptor item in packageList)
{item.Accept(visitor);
}

That mean's: Every pill container allow the PillCountVisitor visitor to see their pills count. 这意味着:每个药丸容器都允许PillCountVisitor访客看到他们的药丸数量。 He know how to count your pill's. 他知道如何计算你的药丸。

At the visitor.Count has the value of pills. visitor.Count具有丸的价值。

In http://butunclebob.com/ArticleS.UncleBob.IuseVisitor you see real scenario in which you can not use polymorphism (the answer) to follow Single Responsibility Principle. 在http://butunclebob.com/ArticleS.UncleBob.IuseVisitor中,您会看到不能使用多态 (答案)遵循单一责任原则的真实场景。 In fact in: 事实上在:

public class HourlyEmployee extends Employee {public String reportQtdHoursAndPay() {//generate the line for this hourly employee}
}

the reportQtdHoursAndPay method is for reporting and representation and this violate the Single Responsibility Principle. reportQtdHoursAndPay方法用于报告和表示,这违反了单一责任原则。 So it is better to use visitor pattern to overcome the problem. 所以最好使用访问者模式来克服这个问题。

我什么时候应该使用访客设计模式? [关闭]相关推荐

  1. 行为设计模式 - 访客设计模式

    行为设计模式 - 访客设计模式 访客设计模式是行为设计​​模式之一. 目录[ 隐藏 ] 1访客设计模式 1.1访客设计模式Java示例 1.2访客设计模式类图 1.3访客模式的好处 1.4访客模式限制 ...

  2. java网页统计访客量_Java中的访客设计模式

    java网页统计访客量 Visitor Design Pattern is one of the behavioral design pattern. 访客设计模式是行为设计​​模式之一. 访客设计模 ...

  3. 访客模式 无痕模式 区别_访客设计模式示例

    访客模式 无痕模式 区别 本文是我们名为" Java设计模式 "的学院课程的一部分. 在本课程中,您将深入研究大量的设计模式,并了解如何在Java中实现和利用它们. 您将了解模式如 ...

  4. 旧访客设计模式的新生活

    介绍 访客 [1.2]是众所周知的经典设计模式. 有很多资源对其进行了详细说明. 在不深入研究实现的情况下,我将简要提醒一下该模式的概念,解释其优点和缺点,并提出一些可以使用Java编程语言轻松应用于 ...

  5. 访客模式 无痕模式 区别_旧访客设计模式的新生活

    访客模式 无痕模式 区别 介绍 访客 [1.2]是众所周知的经典设计模式. 有很多资源对其进行了详细说明. 在不深入研究实现的情况下,我将简要提醒一下该模式的概念,解释其优点和缺点,并提出一些可以使用 ...

  6. 访客模式 无痕模式 区别_访客设计模式

    访客模式 无痕模式 区别 我猜想很多人都知道来访者设计模式,这在<四人帮的设计模式:可重用的面向对象软件的元素>一书中有描述. 模式本身不是很复杂(随着许多设计模式的发展): 我很久以来就 ...

  7. unity3d 收费模式_unity3d中的访客模式

    unity3d 收费模式 抽象 (Abstract) Game development as a discipline is challenging on its own compared to tr ...

  8. 客服系统对接微信公众号-访客在聊天界面扫码-临时访客绑定公众号OpenID可接收客服回复消息通知...

    访客在线咨询有以下几个问题: 1. 访客打开聊天窗口,一般情况下都是临时访客,只存在于当前浏览器. 2. 浏览器清理缓存,或者换一个浏览器,访客ID会重新生成就会变成一个新访客. 3. 访客咨询后,关 ...

  9. Go设计模式--访客模式

    大家好,这里是每周都在陪你一起进步的网管-!今天继续学习设计模式-访客模式 访客模式也叫访问者模式(Visitor Pattern)是一种将数据结构对象与数据操作分离的设计模式,可以在不改变数据结构对 ...

最新文章

  1. 小程序webview跳转页面后没有返回按钮完美解决方案
  2. graph theory important questions
  3. Mybatis执行select语句无匹配对象时返回集为Empty还是null
  4. 订阅插件提示:This system is not registered with an entitlement server. You can use subscription-manager to
  5. mfc 子窗体 按钮不触发_VBA与Excel入门——用户窗体1
  6. centos8.2安装ovirt
  7. ip地址与交换机工作原理
  8. 神经网络论文Enhancing deep neural networks via multiple kernel learning
  9. C语言基础级——N维数组定义与使用
  10. VirtualBox:在linux宿主机和windows虚机间设置共享目录
  11. adm怎么下bt连接_【使用教程】序列模式——福禄克BT系列电池测试仪
  12. 【Unity使用UGUI实现王者荣耀UI界面(四)】游戏开始界面
  13. docker: Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: TLS handshake ti
  14. 联通光猫桥接、路由拨号设置踩坑
  15. mysql中locat函数,MySQL中的LOCATE和POSITION函数使用方法
  16. 2022第13届蓝桥杯Java省赛B组个人题解
  17. 《Python+Kivy(App开发)从入门到实践》自学笔记:简单UX部件——ToggleButton切换按钮
  18. 阿里云服务器搭建wordpress个人博客
  19. HMAC和NMAC 生日攻击
  20. designed for 和designed to 区别

热门文章

  1. java 是怎么跨平台运行的
  2. 金融行业文档管理系统的八大创新
  3. Python-模块和包.深入Celery之子任务及原语组式/链式/回调
  4. register_globals
  5. JAVA如何插入MySql的datetime类型
  6. 如果有一个想法,你如何表述?
  7. Kubernetes 常见问题总结
  8. zabbix监控TCP连接状态
  9. xftp无法链接Linux
  10. Spring boot 配置文件,输入key值,自动补全--- 通过安装插件实现