【问题标题】:Visitor pattern implementation in java- How does this look?java中的访问者模式实现-这看起来如何?
【发布时间】:2009-06-03 13:42:21
【问题描述】:

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() 等。但是,通过使用单个接口访问者,我最终会在访客界面。那是对的吗?你是这样做的吗?

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

【问题讨论】:

    标签: java visitor-pattern


    【解决方案1】:

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

    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 的另一个实现即可。

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

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

    【讨论】:

    • @dfa 策略确实有意义,但是,这将导致策略与业务规则一样多。然后我会有那么多的课——这太多了。在这里使用访问者的想法是,如果我要在我的代码中添加行为,我不应该做太多。
    • "... [如果] 你的数据变化比你的行为慢。" - 这是我听过的关于访客模式的最好描述之一。 +1
    【解决方案2】:

    您的代码存在问题。你给的接口有

    等方法
    public void visitInventory(); 
    

    但您随后在 XYZValidator 中将其实现为

    public void visitInventory(Visitable visitable)
    

    visitor pattern 是一种在不会自动执行此操作的语言(例如 Java)中实现 multiple dispatch 的方法。其中一个要求是您有一组相关的类(即一组具有单个超类的子类)。你这里没有,所以访问者模式不合适。但是,您尝试执行的任务很好,它不是访问者模式。

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

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

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

    【讨论】:

      【解决方案3】:

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

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

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

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

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

      【讨论】:

      • 这意味着,我将拥有与我的业务规则一样多的访客类。这会导致班级爆炸。
      【解决方案4】:

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

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

      可能是不同的访问者实现共享公共活动 - 因此您可以拥有一个定义这些公共功能的超级接口。然后,您可以对 Visitable 接口进行编码以使用特定的 Visitable 接口或它的超类(视情况而定)。

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

      VisitableStore 接受一个 StoreVisitor,

      VisitableFile 接受 Filevisitor,或

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-09-17
        • 1970-01-01
        • 1970-01-01
        • 2013-04-25
        • 1970-01-01
        • 2023-03-28
        相关资源
        最近更新 更多