java java中的访问者模式实现 - 这看起来如何?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/944824/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 14:30:26  来源:igfitidea点击:

Visitor pattern implementation in java- How does this look?

javavisitor-pattern

提问by Jay

Alrite, I am gonna jump straight to the code:

Alrite,我要直接跳到代码:

public interface Visitor {

public void visitInventory(); 
public void visitMaxCount();
public void visitCountry();
public void visitSomethingElse();
public void complete();
//the idea of this visitor is that when a validator would visit it, it would validate data
//when a persister visits it, it would persist data, etc, etc.
// not sure if I making sense here...
}

public interface Visitable {
public void accept(Visitor visitor); 
}

here is a base implementation:

这是一个基本实现:

public class StoreValidator implements Visitor {
private List <ValidationError> storeValidationErrors = new ArrayList<ValidationError>();

public void addError(ValidationError error) {
storeValidationErrors.add(error);
}

public List<ValidationError> getErrors() {
return storeValidationErrors;
}

public void visitInventory() {
// do nothing 
}

public void visitMaxCount() {
//do nothing
}
//... etc..  all empty implementations 

}

You will see why I did an empty implementation here... I would write a validator now.. which extends StoreValidator

你会明白为什么我在这里做了一个空的实现......我现在会写一个验证器......它扩展了 StoreValidator

public XYZValidator extends StoreValidator {

@Override 
public void visitInventory(Visitable visitable) { 
// do something with visitable .. cast it to expected type
// invoke a DAO, obtain results from DB
// if errors found, do addError(new ValidationError()); with msg.
}

@Override 
public void visitMaxCount(Visitable visitable) {
//do something with visitable.. 
}

// I wouldn't implement the rest coz they wouldn't make sense
// in XYZValidator.. so they are defined as empty in StoreValidator.

}

Now here is what a visitable would look like:

现在这是一个可访问的样子:

public Store implements Visitable {

public void accept(Visitor visitor) {
visitor.visitInventory();
visitor.visitMaxCount();
}
}

I could have code that does something like this on a list of Store objects:

我可以有在 Store 对象列表上执行类似操作的代码:

List<Store> stores; //assume this has a list of stores.
StoreValidator validator = new XYZValidator(); //or I would get it from a validatorfactory
for(Store store: stores) {
           store.accept(validator); // so even if you send a wrong validator, you are good.
}

Similarly you would have ABCValidator which would provide implementation for other methods (visitCountry / visitSomethinElse) and it would extend from StoreValidator. I would have another type of Object (not Store) defining accept method.

同样,您将拥有 ABCValidator,它将为其他方法(visitCountry/visitSomethinElse)提供实现,并且它将从 StoreValidator 扩展。我会有另一种类型的对象(不是商店)定义接受方法。

I do see a problem here... Say, I need a FileValidator which is different from StoreValidator, I would expect it to have none of these business related validations such as visitInventory(), etc. But, by having a single interface Visitor, I would endup declaring all kinds of methods in Visitor interface. Is that correct? Is this how you do it?

我确实在这里看到了一个问题......比如说,我需要一个与 StoreValidator 不同的 FileValidator,我希望它没有这些与业务相关的验证,例如visitInventory() 等。但是,通过有一个单一的接口访问者,我最终会在访问者界面中声明各种方法。那是对的吗?你是这样操作的吗?

I don't know if I got the pattern wrong, or if I am making any sense. Please share your thoughts.

我不知道我是否理解错误,或者我是否有任何意义。请分享您的想法。

回答by dfa

Some time ago I wrote something similar for my master thesis. This code is slightly type safe than yours:

前段时间我为我的硕士论文写了类似的东西。这段代码比你的稍微类型安全:

interface Visitable<T extends Visitor> {

   void acceptVisitor(T visitor);
}

interface Visitor {

    /**
     * Called before any other visiting method.
     */
    void startVisit();

    /**
     * Called at the end of the visit. 
     */
    void endVisit();
}

example:

例子:

interface ConstantPoolVisitor extends Visitor {

    void visitUTF8(int index, String utf8);

    void visitClass(int index, int utf8Index);

    // ==cut==
}

class ConstantPool implements Visitable<ConstantPoolVisitor> {

    @Override
    public void acceptVisitor(ConstantPoolVisitor visitor) {
        visitor.startVisit();

        for (ConstanPoolEntry entry : entries) {
            entry.acceptVisitor(visitor);
        }

        visitor.endVisit();
    }

so yes, I think that this definitely a good and flexible design if, and only if, your data changes slower than your behaviour. In my example the data is Java bytecode, that is fixed (defined by the JVM specification). When "behaviour dominates" (I want to dump, compile, transform, refactor, etc my bytecode) the Visitor pattern let you to change/add/remove behaviour without touching your data classes. Just add another implementation of Visitor.

所以是的,我认为这绝对是一个很好且灵活的设计,当且仅当您的数据变化比您的行为慢。在我的示例中,数据是 Java 字节码,它是固定的(由 JVM 规范定义)。当“行为占主导地位”(我想转储、编译、转换、重构等我的字节码)时,访问者模式让您可以在不接触数据类的情况下更改/添加/删除行为。只需添加访问者的另一个实现。

For the sake of simplicity assume that I must add another visit method to my Visitor interface: I would end in breaking all my code.

为简单起见,假设我必须向我的访问者界面添加另一个访问方法:我最终会破坏我的所有代码。

As alternative I would consider the strategy pattern for this scenario. Strategy + decorator is a good design for validation.

作为替代方案,我会考虑这种情况的策略模式。策略+装饰器是一个很好的验证设计。

回答by Kathy Van Stone

There is a problem with your code as given. The interface you give has methods such as

您的代码有问题。您提供的接口具有诸如

public void visitInventory(); 

but you then implement it in XYZValidator as

但是你然后在 XYZValidator 中将它实现为

public void visitInventory(Visitable visitable)

The visitor patternis a way to implement multiple dispatchin languages that do not do that automatically (such as Java). One of the requirements is that you have a group of related classes (i.e. a set of subclasses with a single super class). You don't have that here, so the visitor pattern is not appropriate. The task you are trying to do, however, is fine, it is just not the Visitor pattern.

访问者模式是实现方式的多分派在不这样做,自动(如Java)的语言。其中一个要求是您有一组相关的类(即具有单个超类的一组子类)。你在这里没有,所以访问者模式不合适。但是,您尝试执行的任务很好,只是不是访问者模式。

In Java, you should think of the Visitor pattern if you have code like

在 Java 中,如果你有这样的代码,你应该考虑访问者模式

public void count(Item item) {
  if (item instanceof SimpleItem) {
    // do something
  } else if (item instanceof ComplexItem {
    // do something else
  } else ...
}

particulary if the subclasses of Item are relatively fixed.

特别是如果 Item 的子类相对固定。

回答by AndyT

You probably don't want to map a pattern directly to a single interface that everything following that pattern implements. Patterns are NOT Interfaces, they are general plans for implementing a solution.

您可能不想将模式直接映射到遵循该模式的所有内容都实现的单个接口。模式不是接口,它们是实现解决方案的一般计划。

In your example you would create a StoreVisitor interface and a FileVisitor interface for the different business objects that wish to use the Visitor pattern in the appropriate circumstances.

在您的示例中,您将为希望在适当情况下使用访问者模式的不同业务对象创建一个 StoreVisitor 接口和一个 FileVisitor 接口。

It might be that different Visitor implementations share common activities - so you could have a superinterface that defines those common functions. You could then code Visitable interfaces to use either the specific Visitable interface or it's superclass as appropriate.

可能是不同的访问者实现共享公共活动 - 因此您可以拥有一个定义这些公共功能的超级接口。然后,您可以编写 Visitable 接口的代码,以根据需要使用特定的 Visitable 接口或其超类。

For example, the FileVisitor and SQLTableVisitor interfaces might be a subclass of a DataStoreVisitor interface. Then:

例如,FileVisitor 和 SQLTableVisitor 接口可能是 DataStoreVisitor 接口的子类。然后:

VisitableStore accepts a StoreVisitor,

VisitableStore 接受 StoreVisitor,

VisitableFile accepts a Filevisitor, or

VisitableFile 接受 Filevisitor,或

VisitableDataStore accepts a DataStoreVistor (which might be an implementation of either FileVisitor or SQLTableVisitor).

VisitableDataStore 接受 DataStoreVistor(它可能是 FileVisitor 或 SQLTableVisitor 的实现)。

  • forgive the random examples, I hope this makes sense.
  • 原谅随机的例子,我希望这是有道理的。

回答by Martin Lazar

I'm using a visitor pattern in a different way.. I have a specific Visitor interface for a type of object and this interface declares only one method - for visiting that object.. like this:

我正在以不同的方式使用访问者模式..我有一个特定类型的对象的访问者接口,这个接口只声明一个方法 - 访问该对象..像这样:

public interface TreeNodeVisitor {
    void visit(TreeNode node);
}

the object TreeNodecan accept TreeNodeVisitors which means he just calls it's visitmethod for the node and/or it's children..

对象TreeNode可以接受TreeNodeVisitors,这意味着他只是为节点和/或其子节点调用它的访问方法..

The concrete implementation of the visitor implements the visitmethod and says what the visitor will do.. for example ContryVisitor, InventoryVisitor, etc

访问者的具体实现实现了visit方法并说明了访问者会做什么..例如ContryVisitor、InventoryVisitor等

This approach should avoid your probleam..

这种方法应该可以避免您的问题..