显然,我在整个程序员生活中一直在做一个"非正统的"访客模式.
是的,我从Visitor的Visit方法发送到具体的复合元素访问方法.
我认为这就是我学习它的方法,但是现在我找不到它的任何例子,我从中学到的来源已经消失了.
现在,面对压倒性的证据表明具体的元素调度进入复合元素的Accept方法,我想知道我这样做的方式至少有一些优势.在我看来,两个优点是:
Visit它们来处理它们.这是基本的Composite/Visitor模型:
// "Unorthodox" version
public class BaseVisitor
{
public virtual void Visit(CompositeElement e)
{
if(e is Foo)
{
VisitFoo((Foo)e);
}
else if(e is Bar)
{
VisitBar((Bar)e);
}
else
{
VisitUnknown(e);
}
}
protected virtual void VisitFoo(Foo foo) { }
protected virtual void VisitBar(Bar bar) { }
protected virtual void VisitUnknown(CompositeElement e) { }
}
public class CompositeElement
{
public virtual void Accept(BaseVisitor visitor) { }
} …Run Code Online (Sandbox Code Playgroud) 我正在为Eclipse JDT编写一些简单的AST访问者.我有一个MethodVisitor和FieldVisitor每个扩展的类ASTVisitor.举个MethodVisitor例子.在该类的Visit方法(这是一个覆盖),我能够找到每个MethodDeclaration节点.当我有其中一个节点时,我想查看它Modifiers是否是它(public或者private也许是其他修饰符).有一个方法叫做getModifiers(),但我不清楚如何使用它来确定应用于特定的修饰符的类型MethodDeclaration.我的代码发布在下面,如果您有任何想法如何继续,请告诉我.
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.MethodDeclaration;
public class MethodVisitor extends ASTVisitor {
private List<MethodDeclaration> methods;
// Constructor(s)
public MethodVisitor() {
this.methods = new ArrayList<MethodDeclaration>();
}
/**
* visit - this overrides the ASTVisitor's visit and allows this
* class to visit MethodDeclaration nodes in the AST.
*/
@Override
public boolean visit(MethodDeclaration node) {
this.methods.add(node); …Run Code Online (Sandbox Code Playgroud) java modifier abstract-syntax-tree visitor-pattern eclipse-jdt
我尝试遵循Antlr4 参考书和 Python3 目标,但我陷入了计算器示例。在Antlr4 文档上它说
AntLR 的 Python 实现尽可能接近 Java 实现,因此您应该不会觉得将示例改编为 Python 很困难
但我还没明白。
java代码访问者有一个.visit方法,而在python中我没有这个方法。我认为这是因为在java中访问方法具有令牌的参数重载。在python中我们有visitProg(),等visitAssign()。visitId()但是现在我不能写,value = self.visit(ctx.expr())因为我们不知道要调用什么访问?
或者我在某处遗漏了指令?
我正在研究访问者模式的优点,并引用设计模式:
但是迭代器不能跨具有不同类型元素的对象结构工作。例如,第 295 页定义的 Iterator 接口只能访问 Item 类型的对象:
template <class Item>
clas Iterator { // ... Item CurrentItem() const; };
Run Code Online (Sandbox Code Playgroud)
这意味着迭代器可以访问的所有元素都有一个共同的父类 Item。访客没有此限制...
class Visitor {
public:
// ...
void VisitMyType(MyType*);
void VisitYourType(YourType*);
};
Run Code Online (Sandbox Code Playgroud)
MyType 和 YourType 根本不必通过继承关联。
我同意这句话,但我无法找出访问者模式可以探索List其中收集的对象与超类不相关的结构(如 a )的示例。
换句话说,您能给我举一个例子来证明上述特征是正确的吗?
所以我有一个包含字符串字段的类:
public class A {
private String type = ...
public String getType(){
return this.type;
}
public void setType(String type){
this.type = type;
}
}
Run Code Online (Sandbox Code Playgroud)
我还列出了所有可能的类型,将来有十二种甚至更多.
现在我想编写一个获取类A对象的方法,并根据类中的"类型"调用特定方法.有没有比编写12个(或更多)if语句更聪明的解决方案?
通常我会使用访问者模式,但我不想创建十二个新类.
编辑:
我最终创建了一个
Map<String,Function<A,String>> map = new HashMap<String,Function<A,String>>
Run Code Online (Sandbox Code Playgroud)
然后打电话
A a;
...
map.get(a.getType).apply(a);
Run Code Online (Sandbox Code Playgroud) 我使用了这里给出的访客示例,我们有这个:
.------------------------.
| Flower |
+------------------------+
| +accept(visitor) |
| +pollinate(pollinator) |
| +eat(eater) |
'------------------------'
Run Code Online (Sandbox Code Playgroud)
我们还有可以是 a 的aBug和a ,以及可以是一朵花的 a 。BeepollinateFlowerPredatoreat
使用访问者模式我可以这样写:
bee = Bee()
fly = Fly()
worm = Worm()
# Using the visitor pattern:
for flower in flowerGen(10):
for object in [bee, fly, worm]:
flower.accept(object)
Run Code Online (Sandbox Code Playgroud)
但代码在没有访问者的情况下仍然具有可读性和功能性:
# Without visitor pattern
for flower in flowerGen(10):
for object in [bee, fly, worm]:
object.visit(flower)
Run Code Online (Sandbox Code Playgroud)
问题是,此示例中的访问者模式有哪些优点?
我不知道我在这里是否遗漏了什么,但我无法将对象转换为其实际的初始化类型.基本上,如果我用"SuperClass sc = new SubClass()"创建一个对象,那么我在sc上调用一个方法,我希望该方法能够调用方法(Subclass)而不是方法(Superclass).示例如下:
public class Example
{
public static void act(SuperClass a) {
System.out.println("SuperClass");
}
public static void act(SubClass a) {
System.out.println("SubClass");
}
public static void main(String[] args) {
SuperClass sc = new SubClass();
// want to find a way to call act(SubClass) instead of act(SuperClass)
act(sc);
}
}
class SuperClass {}
class SubClass extends SuperClass {}
Run Code Online (Sandbox Code Playgroud)
我现在正在使用访问者模式,但我想知道是否有其他方法可以通过Java Reflection API进行此操作?
非常感谢提前!
==编辑==
我知道通常使用OO最好将功能强加回超类/子类本身,但对于我的特定用例,我有一堆子类是不可变的模型类,应该传递给不同类型的执行引擎(想想不同的"示例"类).子类/模型类应该只保存不可变信息,而实际的实际功能在于执行引擎(Example类).这就是为什么我想知道访客模式的替代方案.有没有人有办法在Java中恢复实际的"初始化"信息?如果是这样,非常感谢你.
而且由于问题的本质,我不能使用直接投射......想象一下,如果我有一个SuperClass的arraylist,其中每个元素可能是SubClass1,SubClass2,SubClass3,都是从SuperClass扩展的.
现在,当你从Arraylist中取出东西时,你得到一个SuperClass对象,即使它们可能真的是SubClass1,SubClass2,SubClass3等.
接下来,我想调用act(SubClass1),并能够在当前类型上调用正确的act()方法.所以我想最终调用act(SubClass1),act(SubClass2),act(SubClass3),而不是act(SuperClass).
==再次编辑==
我通过Java Reflection API想出了一种方法,通过使用Class.forName(classname)查找SubClass的实际底层类型,然后使用正确的方法签名动态调用该方法.对于那些对此问题感兴趣的人,我已经在本页的某个地方以答案的形式写了这篇文章.请注意,这不是一种非常有效的方式来完成我在这里尝试做的事情,如果你遇到我的情况,你最好使用访问者模式或if-else语句.
所以Nicola Musatti给出的答案最接近于回答我的问题,尽管正如他已经指出的那样,随着SubClasses数量的增长,if-else语句列表变得非常长.我将选择他的答案作为接受答案,因为我在我的问题中没有明确说明我希望避免if-else检查.
无论如何,所以我今天使用Java Reflection API玩了一下并想出了这个:
SuperClass sc = …Run Code Online (Sandbox Code Playgroud) 我尝试使用模板化派生类实现访问者模式
这里是VisitorTemplate.hpp,我专门在类Visitor中派生,但我希望能够处理任何类型:
编辑:感谢interjay的建议,代码现在编译并运行没有错误
#ifndef VISITORTEMPLATE_HPP_
#define VISITORTEMPLATE_HPP_
#include <iostream>
#include <string>
using namespace std;
template<class T> Derived;
class Visitor
{
public:
virtual void visit(Derived<string> *e) = 0;
};
class Base
{
public:
virtual void accept(class Visitor *v) = 0;
};
template<class T>
Derived: public Base
{
public:
virtual void accept(Visitor *v)
{
v->visit(this);
}
string display(T arg)
{
string s = "This is : " + to_string(arg);
return s;
}
};
class UpVisitor: public Visitor
{
virtual void …Run Code Online (Sandbox Code Playgroud) 我有一个父类型
public class IObject{}
Run Code Online (Sandbox Code Playgroud)
并且可以有很多子类(甚至是未来的新子类)
public class Object1 extends IObject{}
public class Object2 extends IObject{}
public class Object3 extends IObject{}
...
public class ObjectN extends IObject{}
Run Code Online (Sandbox Code Playgroud)
然后根据这些对象的类型我必须做不同的操作。
public class StrategyForObject1(){void do{}}
public class StrategyForObject2(){void do{}}
public class StrategyForObject3(){void do{}}
...
public class StrategyForObjectN(){void do{}}
Run Code Online (Sandbox Code Playgroud)
所以我想从我的 Context 类:
public Conext {
IObject o;
public void setObject(IObject o) {
this.o = o;
}
void logic() {
if (o instanceOf Object1) {
new StrategyForObject1().do();
}
if (o instanceOf Object2) {
new StrategyForObject2().do();
} …Run Code Online (Sandbox Code Playgroud) java design-patterns strategy-pattern visitor-pattern genetic-algorithm
Qt的QVariant类是否有任何现有(且方便)的访问者模式实现?
如果没有,是否有可能实现类似的东西boost::apply_visitor(),即最小化测试类型和铸造的重复?
我希望通过以下方式实现目标:
/* I have a QVariant that can contain anything, including user types */
QVariant variant;
/* But in my Visitor I'm interested only in ints and QStrings (for the sake of the example) */
struct Visitor
{
void operator()(int i) { /* do something with int */ }
void operator()(QString s) { /* ...or QString */ }
};
/* The question is: */
/* Can this be implemented in a generic way (without resorting to …Run Code Online (Sandbox Code Playgroud) visitor-pattern ×10
java ×4
c++ ×2
antlr4 ×1
c++11 ×1
eclipse-jdt ×1
field ×1
iterator ×1
modifier ×1
python ×1
python-3.4 ×1
qt ×1
qvariant ×1
templates ×1
visitor ×1