标签: visitor-pattern

我什么时候应该使用访客设计模式?

我一直在博客中看到对访客模式的引用,但我必须承认,我只是不明白.我阅读了维基百科文章的模式,我理解它的机制,但我仍然对我何时使用它感到困惑.

作为最近刚刚获得装饰模式的人,现在看到它在任何地方的用途我都希望能够直观地理解这个看似方便的模式.

design-patterns visitor-pattern

308
推荐指数
14
解决办法
10万
查看次数

对访问者设计模式感到困惑

所以,我只是在阅读访问者模式,我发现访问者和元素之间的来回非常奇怪!

基本上我们称之为元素,我们将其传递给访问者,然后元素将自身传递给访问者。然后访问者操作元素。什么?为什么?感觉太没必要了。我称之为“来回疯狂”。

因此,当需要在所有元素上实施相同的操作时,访问者的意图是将元素与其操作分离。这样做是为了防止我们需要用新动作扩展我们的元素,我们不想进入所有这些类并修改已经稳定的代码。所以我们在这里遵循开放/封闭原则。

为什么会有这一切来回,如果我们没有这些,我们会失去什么?

例如,我编写的这段代码记住了这个目的,但跳过了访问者模式的疯狂交互。基本上我有会跳跃和进食的动物。我想将这些动作与对象分离,所以我将动作移到了访客。吃和跳会增加动物的健康(我知道,这是一个非常愚蠢的例子......)

public interface AnimalAction { // Abstract Visitor
    public void visit(Dog dog);
    public void visit(Cat cat);
}

public class EatVisitor implements AnimalAction { // ConcreteVisitor
    @Override
    public void visit(Dog dog) {
        // Eating increases the dog health by 100
        dog.increaseHealth(100);
    }

    @Override
    public void visit(Cat cat) {
        // Eating increases the cat health by 50
        cat.increaseHealth(50);
    }
}

public class JumpVisitor implements AnimalAction { // ConcreteVisitor
    public void visit(Dog dog) {
        // Jumping increases the dog …
Run Code Online (Sandbox Code Playgroud)

java design-patterns visitor visitor-pattern

38
推荐指数
3
解决办法
3776
查看次数

访客模式+开放/封闭原则

是否可以实现尊重开放/封闭原则访客模式,但仍然能够添加新的可访问类?

开放/封闭原则规定"软件实体(类,模块,功能等)应该开放以进行扩展,但是关闭以进行修改".

struct ConcreteVisitable1;
struct ConcreteVisitable2;

struct AbstractVisitor
{
   virtual void visit(ConcreteVisitable1& concrete1) = 0;
   virtual void visit(ConcreteVisitable2& concrete2) = 0;
};

struct AbstractVisitable
{
   virtual void accept(AbstractVisitor& visitor) = 0;
};

struct ConcreteVisitable1 : AbstractVisitable
{
   virtual void accept(AbstractVisitor& visitor)
   {
      visitor.visit(*this);
   }
};

struct ConcreteVisitable2 : AbstractVisitable
{
   virtual void accept(AbstractVisitor& visitor)
   {
      visitor.visit(*this);
   }
};
Run Code Online (Sandbox Code Playgroud)

您可以实现任意数量的派生自AbstractVisitor的类:它是可以扩展的.您无法添加新的可访问类,因为从AbstractVisitor派生的类将无法编译:它已关闭以进行修改.

AbstractVisitor类树遵循开放/封闭原则.AbstractVisitable类树不遵循开放/封闭原则,因为它无法扩展.

除了扩展AbstractVisitor和AbstractVisitable之外还有其他解决方案吗?

struct ConcreteVisitable3;

struct AbstractVisitor2 : AbstractVisitor
{
   virtual void visit(ConcreteVisitable3& concrete3) = 0;
};

struct …
Run Code Online (Sandbox Code Playgroud)

c++ oop design-patterns visitor-pattern open-closed-principle

16
推荐指数
1
解决办法
1690
查看次数

双重调度如何在访客模式中工作?

我正在研究与访问者模式相关的其他问题,但无法理解访问者模式中双重调度的实现.

请参阅访问者模式链接

双重调度如何在访客模式中工作?

java design-patterns double-dispatch visitor-pattern

16
推荐指数
3
解决办法
9060
查看次数

如何在C#中为抽象语法树编写访问者模式?

我必须写一个访问者模式来导航AST.任何人都可以告诉我更多我将如何开始写它?据我所知,AST中的每个节点都有visit()方法(?),它会以某种方式被调用(从哪里?).这总结了我的理解.为了简化一切,假设我有节点Root,Expression,Number,Op,树看起来像这样:

      Root
        |
       Op(+)
      /   \
     /     \
 Number(5)  \
             Op(*)
             /   \
            /     \
           /       \
       Number(2)   Number(444)
Run Code Online (Sandbox Code Playgroud)

c# abstract-syntax-tree visitor-pattern

14
推荐指数
1
解决办法
6469
查看次数

如何在javascript中实现访问者模式?

据我所知,访问者模式通常用于向某些层次结构添加方法.但我仍然没有得到它:看到我尝试突出显示左子树的示例:

子树突出显示

Javascript树实现:

  function node(val) {
    this.value = val;
    this.left = this.right = null;
  }

  var tree = new node("A");
  tree.left = new node("B1");
  tree.right = new node("B2");
  tree.left.left = new node("C1");
  tree.left.right = new node("C2");
Run Code Online (Sandbox Code Playgroud)

我想我正在使用访客模式突出显示:

node.prototype.accept = function(visitorObj) {
  visitorObj.visit(this);
}

function visitor() {
  var that = this;
  this.visit = function(tgt) {
    tgt.value = "*"+tgt.value;
  }
  this.highlight = function(tgt) {
    tgt.accept(that);
    if(tgt.left) that.highlight(tgt.left);
    if(tgt.right) that.highlight(tgt.right);
  }
}

(new visitor()).highlight(tree.left);
Run Code Online (Sandbox Code Playgroud)

但是为什么要使用接受访问方法,何时可以更直接?

function visitor() {
  var that = this; …
Run Code Online (Sandbox Code Playgroud)

javascript design-patterns visitor-pattern

12
推荐指数
1
解决办法
6215
查看次数

访客模式的实际优势是什么?有哪些替代方案?

我读了很多关于访客模式及其所谓的优点.然而,对我而言,在实践中应用它们似乎并没有那么多优点:

  • "方便"和"优雅"似乎意味着大量的样板代码
  • 因此,代码很难遵循."接受"/"访问"也不是很具描述性
  • 如果您的编程语言没有方法重载(即Vala),甚至更糟糕的样板代码
  • 您通常不能在不修改所有类的情况下向现有类型层次结构添加新操作,因为只要您需要具有不同参数和/或返回值的操作(类更改),您就需要在任何地方使用新的"接受"/"访问"方法到处都是这个设计模式应该避免的一件事!?)
  • 向类型层次结构添加新类型需要更改所有访问者.此外,您的访问者不能简单地忽略类型 - 您需要创建一个空访问方法(样板再次)

当你想要做的事实上是这样的时候,这一切似乎都是非常多的工作:

// Pseudocode
int SomeOperation(ISomeAbstractThing obj) {
    switch (type of obj) {
        case Foo: // do Foo-specific stuff here
        case Bar: // do Bar-specific stuff here
        case Baz: // do Baz-specific stuff here
        default: return 0; // do some sensible default if type unknown or if we don't care
    }
}
Run Code Online (Sandbox Code Playgroud)

我看到的唯一真正的优势(我在任何地方都没有看到过):访问者模式可能是在cpu时间方面实现上述代码片段的最快方法(如果你没有双重调度的语言或者以上述伪代码的方式进行有效的类型比较).

问题:

  • 那么,我错过了访客模式的哪些优势?
  • 可以使用哪些替代概念/数据结构来使上述虚构代码示例同样快速运行?

language-agnostic visitor-pattern

11
推荐指数
3
解决办法
3269
查看次数

什么是单一和双重调度?

我写了访客模式如下,但我不明白什么是单一和双重调度.AFAIK,单个调度是基于调用者类型调用方法,其中double dispatch根据调用者类型和参数类型调用方法.

我想双重调度是在单个类层次结构中发生的,但是为什么访问者类有两个类层次结构但它仍然被认为是双重调度.

void floppyDisk::accept(equipmentVisitor* visitor)
{
 visitor->visitFloppyDisk(this);
}

void processor::accept(equipmentVisitor* visitor)
{
 visitor->visitProcessor(this);
}

void computer::accept(equipmentVisitor* visitor)
{
 BOOST_FOREACH(equipment* anEquip, cont)
 {
  anEquip->accept(visitor);
 }

 visitor->visitComputer(this);
}

void visitFloppyDisk(floppyDisk* );
void visitProcessor(processor* );
void visitComputer(computer* );
Run Code Online (Sandbox Code Playgroud)

请使用我提供的示例代码进行解释.

AFAIK,第一次调度发生在调用accept的对象上,第二次调度发生在调用visit方法的对象上.

谢谢.

c++ design-patterns double-dispatch visitor-pattern

9
推荐指数
2
解决办法
8025
查看次数

C++:对访问者模式的怀疑

我知道访客模式是什么以及如何使用它; 这个问题是不是这个的副本一个.


我有一个库,我把大部分可重复使用的代码放在我写的,并链接到我的大多数项目.

我经常需要为某些类添加功能,但不将这些新功能添加到库中.让我用一个真实的例子:

在这个lib中,我有一个类Shape,继承自CircleShape,PolygonShapeCompositeShape.

我现在正在开发一个图形应用程序,我需要渲染它们Shape,但不想render在核心Shape类中放置虚函数,因为我使用的一些项目Shape不进行任何渲染,而其他图形项目可以使用不同的渲染引擎(我在这个项目中使用Qt,但对于我使用OpenGL的游戏,因此该render函数需要不同的实现).

最着名的方法是使用访客模式,当然,这会让我心中产生一些疑问:

任何类的任何库都需要像我Shape一样扩展.大多数公共图书馆(大约所有公共图书馆)都没有为访客模式提供任何支持; 为什么?我为什么要?

访问者模式是一种在C++中模拟Double Dispatching的方法.它在C++中不是原生的,需要显式实现,使得类接口更复杂:我认为applyVisitor函数不应该与我的类函数处于同一级别,我认为这就像打破抽象.

明确的向上铸造Shapedynamic_cast比较昂贵,但对我来说,它看起来像一个清晰的解决方案.


所以我该怎么做?在我的所有库类中实现Double Dispatching?如果图书馆提供的Shape不是我的,但在互联网上找到了一些GPL库怎么办?

c++ double-dispatch visitor-pattern

9
推荐指数
1
解决办法
2810
查看次数

访客和策略模式之间有什么区别?

我已经学会了这两种模式但却不理解这两种模式之间的差异.

我不知道场景,何时何地使用这些模式.

任何人都可以解释差异和用例吗?

java design-patterns strategy-pattern visitor-pattern

9
推荐指数
3
解决办法
3950
查看次数