java 中的访问者模式实现 - 这看起来怎么样?

发布于 2024-07-23 06:20:33 字数 2439 浏览 5 评论 0原文

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); 
}

这是一个基本实现:

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 

}

您会明白为什么我在这里做了一个空实现...我现在会编写一个验证器..它扩展了 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.

}

现在这是可访问的样子:

public Store implements Visitable {

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

我可以有代码在 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.
}

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

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

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

Alrite, I am gonna jump straight to the code:

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

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:

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.

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?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

乖乖兔^ω^ 2024-07-30 06:20:33

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

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();
}

示例:

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();
    }

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

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

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

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.

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.

还如梦归 2024-07-30 06:20:33

您给定的代码有问题。 您提供的接口具有诸如此类的方法

public void visitInventory(); 

,但您随后在 XYZValidator 中实现它,因为

public void visitInventory(Visitable visitable)

访问者模式 是一种在不自动执行的语言(例如 Java)中实现多重调度的方法。 其中一个要求是您有一组相关的类(即一组具有单个超类的子类)。 这里没有,所以访问者模式不合适。 然而,您尝试执行的任务很好,它只是不是访客模式。

您应该考虑访问者模式。

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

在 Java 中,如果您有这样的代码,特别是如果 Item 的子类相对固定,

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

public void visitInventory(Visitable visitable)

The visitor pattern is a way to implement multiple dispatch in 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.

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

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.

以往的大感动 2024-07-30 06:20:33

我以不同的方式使用访问者模式..我有一个针对某种类型的对象的特定访问者接口,并且该接口仅声明一个方法 - 用于访问该对象..如下所示:

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

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

访问者的具体实现实现了visit< /strong> 方法并说明访问者将执行的操作。例如 ContryVisitor、InventoryVisitor 等

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

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 TreeNode can accept TreeNodeVisitors which means he just calls it's visit method for the node and/or it's children..

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

This approach should avoid your probleam..

小苏打饼 2024-07-30 06:20:33

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

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

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

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

VisitableStore 接受 StoreVisitor,

VistableFile 接受 Filevisitor,或

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

  • 请原谅随机的例子,我希望这是有道理的。

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.

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.

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

VisitableStore accepts a StoreVisitor,

VisitableFile accepts a Filevisitor, or

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

  • forgive the random examples, I hope this makes sense.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文