- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在修改我以前使用的Visitor模式。我们有基类Element,它具有虚拟方法accept(Visitor),并且此方法在从Element继承的所有类中均被覆盖。在任何派生类中,accept()所做的全部工作就是调用visitor-> visit(* this)。现在,当客户端运行代码时,他/她将执行以下操作:
Visitor& theVisitor = *new ConcreteVisitor();
for_each(elements.begin(), elements.end(), [](Element& e) { e.accept(theVisitor));})
Visitor& theVisitor = *new ConcreteVisitor();
for_each(elements.begin(), elements.end(), [&theVisitor](Element& e) { theVisitor.visit(e); });
最佳答案
长期以来,我一直对“访客”模式感到困惑,并且我一直试图在Internet上找到各种解释,而这些解释使我更加困惑。现在,我了解了为什么需要访问者模式的原因以及实现方式,所以这里是:
需要访客模式来解决“双重调度”问题。
单一调度-当您具有一个类层次结构并且在该层次结构中有一个具体类的实例时
并且您想为此实例调用适当的方法。这可以通过函数重写(使用C++中的虚拟函数表)解决。
双重调度是指当您有两个类层次结构,并且在一个层次结构中有一个具体类实例,而在另一个层次结构中有一个具体类实例时,您想调用将对这两个特定实例起作用的适当方法。
让我们来看一个例子。
头等舱等级:动物。基础:Animal
,派生:Fish
,Mammal
,Bird
。
第二类层次结构:调用程序。基础:Invoker
,派生:MovementInvoker
(移动动物),VoiceInvoker
(使动物发声),FeedingInvoker
(喂养动物)。
现在,对于每种特定的动物和每种特定的调用程序,我们只希望调用一个特定的函数来完成特定的工作(例如,喂鸟或给鱼听起来)。因此,总共有3x3 = 9个函数可以完成这些工作。
另一个重要的事情是:运行这9个功能中的每一个的客户都不想知道他或她手头有什么具体的Animal
和什么具体的Invoker
。
因此,客户希望执行以下操作:
void act(Animal& animal, Invoker& invoker)
{
// Do the job for this specific animal using this specific invoker
}
void act(vector<shared_ptr<Animal>>& animals, vector<shared_ptr<Invoker>>& invokers)
{
for(auto& animal : animals)
{
for(auto& invoker : invokers)
{
// Do the job for this specific animal and invoker.
}
}
}
Animal
和此特定
Invoker
的9种(或任何其他)特定方法之一?
Animal
的虚拟方法(使用虚拟函数表,它将在
Animal
类层次结构中找到具体实例的具体功能),还需要调用
Invoker
的虚拟方法(它将找到具体的调用者) 。
#ifndef __VISITOR__
#define __VISITOR__
struct Invoker; // forward declaration;
// -----------------------------------------//
struct Animal
{
// The name of the function can be anything of course.
virtual void accept(Invoker& invoker) = 0;
};
struct Fish : public Animal
{
void accept(Invoker& invoker) override;
};
struct Mammal : public Animal
{
void accept(Invoker& invoker) override;
};
struct Bird : public Animal
{
void accept(Invoker& invoker) override;
};
// -----------------------------------------//
struct Invoker
{
virtual void doTheJob(Fish& fish) = 0;
virtual void doTheJob(Mammal& Mammal) = 0;
virtual void doTheJob(Bird& Bird) = 0;
};
struct MovementInvoker : public Invoker
{
void doTheJob(Fish& fish) override;
void doTheJob(Mammal& Mammal) override;
void doTheJob(Bird& Bird) override;
};
struct VoiceInvoker : public Invoker
{
void doTheJob(Fish& fish) override;
void doTheJob(Mammal& Mammal) override;
void doTheJob(Bird& Bird) override;
};
struct FeedingInvoker : public Invoker
{
void doTheJob(Fish& fish) override;
void doTheJob(Mammal& Mammal) override;
void doTheJob(Bird& Bird) override;
};
#endif
#include <iostream>
#include <memory>
#include <vector>
#include "visitor.h"
using namespace std;
// -----------------------------------------//
void Fish::accept(Invoker& invoker)
{
invoker.doTheJob(*this);
}
void Mammal::accept(Invoker& invoker)
{
invoker.doTheJob(*this);
}
void Bird::accept(Invoker& invoker)
{
invoker.doTheJob(*this);
}
// -----------------------------------------//
void MovementInvoker::doTheJob(Fish& fish)
{
cout << "Make the fish swim" << endl;
}
void MovementInvoker::doTheJob(Mammal& Mammal)
{
cout << "Make the mammal run" << endl;
}
void MovementInvoker::doTheJob(Bird& Bird)
{
cout << "Make the bird fly" << endl;
}
// -----------------------------------------//
void VoiceInvoker::doTheJob(Fish& fish)
{
cout << "Make the fish keep silence" << endl;
}
void VoiceInvoker::doTheJob(Mammal& Mammal)
{
cout << "Make the mammal howl" << endl;
}
void VoiceInvoker::doTheJob(Bird& Bird)
{
cout << "Make the bird chirp" << endl;
}
// -----------------------------------------//
void FeedingInvoker::doTheJob(Fish& fish)
{
cout << "Give the fish some worms" << endl;
}
void FeedingInvoker::doTheJob(Mammal& Mammal)
{
cout << "Give the mammal some milk" << endl;
}
void FeedingInvoker::doTheJob(Bird& Bird)
{
cout << "Give the bird some seed" << endl;
}
int main()
{
vector<shared_ptr<Animal>> animals = { make_shared<Fish> (),
make_shared<Mammal> (),
make_shared<Bird> () };
vector<shared_ptr<Invoker>> invokers = { make_shared<MovementInvoker> (),
make_shared<VoiceInvoker> (),
make_shared<FeedingInvoker> () };
for(auto& animal : animals)
{
for(auto& invoker : invokers)
{
animal->accept(*invoker);
}
}
}
Make the fish swim
Make the fish keep silence
Give the fish some worms
Make the mammal run
Make the mammal howl
Give the mammal some milk
Make the bird fly
Make the bird chirp
Give the bird some seed
Animal
实例和一个
Invoker
实例并调用
animal.accept(invoker)
时,会发生什么?
Animal
的实例为
Bird
,而
Invoker
的实例为
FeedingInvoker
。
Bird::accept(Invoker&)
将被调用,该表将依次运行
invoker.doTheJob(Bird&)
。
Invoker
实例是
FeedingInvoker
,因此虚拟函数表将使用
FeedingInvoker::accept(Bird&)
进行此调用。
Bird
和
FeedingInvoker
调用了正确的方法(9种可能的方法之一)。
Insect
),则无需更改现有的Animal
层次结构。doTheJob(Insect& insect)
和所有派生的调用者中添加:Invoker
。 Invoker
会被
Visitor
替换,
doTheJob()
会被
visit()
替换,但对我来说,这些名称实际上并不反射(reflect)对元素执行某些操作的事实)。
关于c++ - 为什么我们需要访问者模式中的accept()以及为什么我们不能直接调用visitor.visit()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50387849/
在维基百科中 sample在 GoF 书中,访问者模式的使用是通过调用某些接受器上的 accept 方法开始的。但是为什么会这样呢?为什么我们不能以所需的接受器作为参数开始调用 visit 方法?我们
我正在尝试制作antrl4 4.6。工作,但我收到 4 个高级错误,我无法解决它们。有人可以帮我吗?也许需要匿名类。 还有 super() 错误,我将它放在正确的位置,但它拒绝工作。 Yoco.jav
跟踪特定页面的页面浏览量(特别是独特的)的最佳方法是什么? 示例:论坛中的话题、视频网站中的视频、问答脚本 (SO) 中的问题。 目前,我正在尝试为每一行采用一个简单的“浏览量”列来计算浏览量,但是,
在我对 Rust 的有限理解中,我认为 trait 就像接口(interface)——当你实现一个接口(interface)时,你需要实现所有的方法。 我现在正在编写自定义 serde::Deseri
我正在做一个关于访问者设计模式的演示,我了解它是如何工作的,但我还没有找到“定义的”优点和缺点,而且我不想自己推测优点或缺点,因为我可以设置虚假信息。 最佳答案 以下是我对 Visitor 的一些想法
我正在做一个关于访问者设计模式的演示,我了解它是如何工作的,但我还没有找到“定义的”优点和缺点,而且我不想自己推测优点或缺点,因为我可以设置虚假信息。 最佳答案 以下是我对 Visitor 的一些想法
访问者模式表示一个作用于某对象结构中各元素的操作。它可以在不修改各元素类的前提下定义作用于这些元素的新操作,即动态的增加具体访问者角色。 访问者模式利用了双重分派。先将访问者传入元素对象的Accep
代码如下: <?php /** * 访问者模式 * * 表示一个作用于某对象结构中的各元素的操作,可以在不改变各元素的类的前提下定义作用于这
访问者模式(Visitor Pattern)使用了一个访问者类,它改变了元素类的执行算法,通过这种方式,元素的执行算法可以随着访问者改变而改变 访问者模式中,元素对象已接受访问者对象,这样访问者对象
我尝试使用三种不同的方法提取特定目录的(唯一)访问者计数: * 有简介 * 使用动态高级段 * 使用自定义报告过滤器 在较小的站点上,这三种方法给出相同的结果。但是在大型网站(> 500 万次访问/月
我使用 boost::variant 制作了一个程序,但不知何故 const 不正确。 错误:将“const CompareTitle”作为“bool CompareTitle::operator()
我正在开发一个应用程序的设计,我想我可能会应用某种 Visitor design pattern ,但事实证明这并不是我要找的。也许有人可以指出我在这种情况下需要的变体? 我的大部分代码都有一个模板参
我正在寻找一种简洁的设计来模拟 Visitor 的功能,而没有它的许多缺点。在 Java 中,传统的实现(如 GoF 中所述)采用双重分派(dispatch)来摆脱 if-elses。为了解决这个问题
关闭。这个问题需要details or clarity .它目前不接受答案。 想改进这个问题吗? 通过 editing this post 添加细节并澄清问题. 关闭 9 年前。 Improve t
我正在尝试编写一个简单的脚本系统(用于视频游戏),其中没有非常复杂的任务,只有简单的 bool 检查和操作集。 我是一名学生,但我不是在学习编程,我只是把它作为一种爱好,所以我正在学习基础知识,最近我
我使用类似 STL 的迭代器在 C++ 中实现了访问者模式,用于存储访问者在容器中的当前位置。现在我想在迭代容器时更改容器,我特别感兴趣的是从容器中删除项目,即使是我当前正在访问的项目。 现在显然这将
我正在尝试以参数化方式实现访问者模式的修改版本,以这种方式避免“通用访问者”对每个具体元素都有过载,但是,由于我没有太多经验在模板编程中,我不知道如何完成“模式”。 代码: // test.cpp #
我没有看到有效的示例,而且我看到一些拉取请求仍处于打开状态。我想避免沿着花园小径走。 https://github.com/antlr/antlr4/pull/1807 https://github.
双重分发(double dispatch) 什么是双重分发? 谈起面向对象的程序设计时,常说起的面向对象的「多态」,其中关于多态,经常有一个说法是「父类引用指向子类对象」。 这种父类的引用指向
本文整理了Java中org.raml.parser.visitor.YamlValidator类的一些代码示例,展示了YamlValidator类的具体用法。这些代码示例主要来源于Github/Sta
我是一名优秀的程序员,十分优秀!