标签: visitor

访客模式的目的与示例

我对访客模式及其用途感到困惑.我似乎无法想象使用这种模式或其目的的好处.如果有人可以用例子解释,如果可能的话会很好.

java design-patterns visitor

83
推荐指数
3
解决办法
3万
查看次数

访客模式中accept()方法的重点是什么?

关于将算法与类分离的讨论很多.但是,有一件事没有解释.

他们像这样使用访客

abstract class Expr {
  public <T> T accept(Visitor<T> visitor) {visitor.visit(this);}
}

class ExprVisitor extends Visitor{
  public Integer visit(Num num) {
    return num.value;
  }

  public Integer visit(Sum sum) {
    return sum.getLeft().accept(this) + sum.getRight().accept(this);
  }

  public Integer visit(Prod prod) {
    return prod.getLeft().accept(this) * prod.getRight().accept(this);
  }
Run Code Online (Sandbox Code Playgroud)

Visitor不会直接调用visit(element),而是要求元素调用其visit方法.它与所宣称的关于访客的阶级无意识的观念相矛盾.

PS1请用您自己的话解释或指出确切的解释.因为我得到的两个回答是指一般的和不确定的.

PS2我的猜测:由于getLeft()返回基本Expression,调用visit(getLeft())将导致visit(Expression),而getLeft()调用visit(this)将导致另一个更合适的访问调用.因此,accept()执行类型转换(也称为转换).

PS3 Scala的模式匹配=类固醇上的访客模式显示没有接受方法访问者模式的简单程度.维基百科补充说:通过链接一篇论文,显示" accept()当反射可用时,方法是不必要的;为该技术引入术语'Walkabout'."

design-patterns visitor

77
推荐指数
2
解决办法
2万
查看次数

访客模式的替代方案?

我正在寻找访客模式的替代方案.让我只关注模式的几个相关方面,同时跳过不重要的细节.我将使用Shape示例(抱歉!):

  1. 您有一个实现IShape接口的对象层次结构
  2. 您有许多要在层次结构中的所有对象上执行的全局操作,例如Draw,WriteToXml等...
  3. 很容易直接潜入并向IShape接口添加Draw()和WriteToXml()方法.这不一定是件好事 - 每当你想添加一个要对所有形状执行的新操作时,每个IShape派生类都必须改变
  4. 为每个操作实现访问者,即Draw访问者或WirteToXml访问者在一个类中封装该操作的所有代码.然后,添加新操作就是创建一个新的访问者类,该类对所有类型的IShape执行操作
  5. 当你需要添加一个新的IShape派生类时,你基本上遇到了与3中相同的问题 - 必须更改所有访问者类以添加一个方法来处理新的IShape派生类型

你阅读有关访客模式的大多数地方表明第5点几乎是模式工作的主要标准,我完全同意.如果修改了IShape派生类的数量,那么这可能是一种非常优雅的方法.

所以,问题是当添加一个新的IShape派生类时 - 每个访问者实现需要添加一个新方法来处理该类.这充其量是令人不愉快的,在最坏的情况下,这是不可能的,并且表明这种模式并非真正设计用于应对这种变化.

所以,问题是有没有人遇到过处理这种情况的替代方法?

oop design-patterns visitor

51
推荐指数
3
解决办法
2万
查看次数

访客模式和双重调度之间的差异

我正在阅读有关访客模式的内容,它看起来像Double Dispatch.两者之间有什么区别吗?这两个术语是否意思相同.

参考:http://www.vincehuston.org/dp/visitor.html

design-patterns double-dispatch visitor

48
推荐指数
4
解决办法
1万
查看次数

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

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

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

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

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

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

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
查看次数

如何制作更安全的C++变体访问者,类似于switch语句?

许多人使用C++ 17/boost变体的模式看起来与switch语句非常相似.例如:( 来自cppreference.com的片段)

std::variant<int, long, double, std::string> v = ...;

std::visit(overloaded {
    [](auto arg) { std::cout << arg << ' '; },
    [](double arg) { std::cout << std::fixed << arg << ' '; },
    [](const std::string& arg) { std::cout << std::quoted(arg) << ' '; },
}, v);
Run Code Online (Sandbox Code Playgroud)

问题是当您在访问者中输入错误的类型或更改变体签名时,但忘记更改访问者.您将获得错误的lambda,通常是默认的lambda,而不是获得编译错误,或者您可能会得到一个您没有计划的隐式转换.例如:

v = 2.2;
std::visit(overloaded {
    [](auto arg) { std::cout << arg << ' '; },
    [](float arg) { std::cout << std::fixed << arg << ' '; } // oops, this won't …
Run Code Online (Sandbox Code Playgroud)

c++ visitor variant switch-statement c++17

30
推荐指数
1
解决办法
3676
查看次数

为什么要使用访客模式?

重复:我应该何时使用访客设计模式

为什么有人想要使用访客模式?我读了几篇文章,但我没有得到什么.

如果我需要一个功能来收取定制,我可以使用

Custom.Accept(BillVisitor)
Run Code Online (Sandbox Code Playgroud)

或类似的东西

Bill(Customer)
Run Code Online (Sandbox Code Playgroud)

第二个不太复杂,Bill函数仍然与Customer类分开.那么我为什么要使用访客模式呢?

design-patterns visitor

27
推荐指数
2
解决办法
3万
查看次数

用lambdas进行变异访问的最佳方法

我想用lambdas内联访问变体类型.目前我有以下代码:

struct Foo {
    boost::variant< boost::blank , int , string , vector< int >  > var;

    template <typename T, typename IL , typename SL , typename VL>
    void ApplyOptionals( T& ref, IL&& intOption , SL&& stringOption , VL&& vectorOption ) {
        if (var.which() == 1) {
            intOption( ref , boost::get< int >(var) );
        } else if (var.which() ==2) {
            stringOption( ref , boost::get< string>(var) );
        } else if (var.which() == 3) {
            vectorOption( ref , boost::get< vector< int > >(var) …
Run Code Online (Sandbox Code Playgroud)

c++ lambda visitor boost-variant c++11

27
推荐指数
1
解决办法
7017
查看次数

访客模式如何不违反开放/封闭原则?

来自维基百科:

这个想法是,一旦完成,只能修改类的实现以纠正错误; 新功能或更改功能需要创建不同的类.该类可以通过继承重用原始类中的编码

根据我的理解,访问者模式是一种强大的技术,可以遍历使用双重调度实现相同接口的相似但不同的对象.在我的一个Java示例中,我创建了一组形成树结构的复合对象,这些对象的每个特定实现都实现了可访问的接口.访问者界面具有用于每个可访问对象的方法,并且具体访问者实现对每个这些情况执行的操作.

我试图解决的问题是,如果我要在复合结构中添加一个也实现可访问的新实现,那么我需要重新打开访问者界面并将该情况添加到它,也迫使我修改访问者的每个实现.

虽然这很好,但我还是需要这样做(如果访问者无法理解,那么访问者增加了什么好处?)但是在学术层面上,这不会违反开放封闭原则吗?这不是设计模式的核心原因之一吗?试图显示转换到这种模式的合理理由而不是维护switch语句来结束所有switch语句,但是每个人都认为代码将是相同的,每种情况的方法而不是交换机块,只是分解并且更难阅读.

java design-patterns visitor open-closed-principle

27
推荐指数
2
解决办法
2046
查看次数

访客模式解释

所以我已经阅读了有关访客模式的所有文档,我仍然非常困惑.我从另一个问题中得到了这个例子,有人能帮我理解吗?例如,我们何时使用访客设计模式?我想我可能已经理解了一些,但我只是无法看到更大的图景.我如何知道何时可以使用它?

class equipmentVisited
{
  virtual void accept(equipmentVisitor* visitor) = 0;
}

class floppyDisk : public equipmentVisited
{
  virtual void accept(equipmentVisitor* visitor);
}

class processor : public equipmentVisited
{
  virtual void accept(equipmentVisitor* visitor);
}

class computer : public equipmentVisited
{
  virtual void accept(equipmentVisitor* visitor);
}

class equipmentVisitor
{
  virtual void visitFloppyDisk(floppyDisk* );
  virtual void visitProcessor(processor* );
  virtual void visitComputer(computer* );
}

// Some additional classes inheriting from equipmentVisitor would be here

equipmentVisited* visited;
equipmentVisitor* visitor;

// Here you initialise visited and …
Run Code Online (Sandbox Code Playgroud)

c++ visitor

25
推荐指数
2
解决办法
2万
查看次数