【问题标题】:Extend Visitor pattern without modifying the original source code?在不修改原始源代码的情况下扩展访问者模式?
【发布时间】:2014-10-10 13:59:36
【问题描述】:

我在跨多个模块扩展访问者模式时遇到问题,您可以阅读 cmets 中的问题说明。

interface Example {

    interface ISource {
        Object accept(ISourceVisitor visitor);
    }

    class Module1Source1 implements ISource {
        @Override
        public Object accept(ISourceVisitor visitor) {
            return visitor.visit(this);
        }
    }

    class Module1Source2 implements ISource {
        @Override
        public Object accept(ISourceVisitor visitor) {
            return visitor.visit(this);
        }
    }

    interface ISourceVisitor {
        Object visit(Module1Source1 wheel);
        Object visit(Module1Source2 engine);
    }

    class SupportedCurrenciesVisitor implements ISourceVisitor {
        @Override
        public Object visit(Module1Source1 wheel) {
            return ImmutableList.of("USD");
        }

        @Override
        public Object visit(Module1Source2 engine) {
            return ImmutableList.of("EUR");
        }
    }

    //suppose we don't want to change the code above because it's in another library
    //I want to add one more source

    class Module2Source1 implements ISource {
        @Override
        public Object accept(ISourceVisitor visitor) {
            return null;
        }
    }

    // I cannot change ISourceVisitor, so what do I need to do?
    // one way is to create another interface

    interface IAnotherModuleSource extends ISource {
        Object accept(IThisModuleSourceVisitor visitor);
    }

    interface IThisModuleSourceVisitor extends ISourceVisitor {
        Object visit(Module2Source2 module2Source2);
    }

    class Module2Source2 implements IAnotherModuleSource {
        //it's ok
        @Override
        public Object accept(IThisModuleSourceVisitor visitor) {
            return visitor.visit(this);
        }
        //but what should we do with this:??
        @Override
        public Object accept(ISourceVisitor visitor) {
            return accept((IThisModuleSourceVisitor) visitor);
        }

        //this way if SupportedCurrenciesVisitor will be passed to the Module2Source2 we 
        //will have CCE
        //but it's ok if we pass here specific visitor for this module
    }

}

显然,如果我们将 getSupportedCurrencies() 方法放在 ISource 中 不会有这样的问题,但我想这也不是完美的方式。

问题是我们可以对访客做得更好吗?

或者在这种情况下您建议的方法是什么?

【问题讨论】:

  • 您可以对基本访问者使用一些默认操作:打印日志条目和/或抛出异常以在其他地方处理。为什么你认为有更好的选择?
  • 因为我认为外面有比我更聪明的人=),我也考虑过例外但我们会等待,也许有人会想出另一个主意。
  • 好吧,让代码在没有 CCE 的情况下工作的一种选择:class Module2Source2 extends Module1Source1 implements IAnotherModuleSource。但我不知道你是否可以接受。
  • 与问题无关,但尽管有 Wikipedia 的示例,但现代高级语言中普遍放弃了匈牙利符号。

标签: java design-patterns visitor-pattern extensibility


【解决方案1】:

Tl;dr:您所描述的问题是尝试将模式应用于不适合的问题的结果。

“改变的原因”都属于 2 个基本类别:数据和功能。访问者模式将数据和功能之间的正常 OO 直接关联解耦,让您牺牲更改数据结构的能力以换取能够非常轻松地更改功能。添加另一个ISourceVisitor 将是微不足道的,因为这就是访客模式旨在让您做的事情。添加另一个 ISource 会更改您的数据结构并迫使您更改所有功能以适应它,这肯定表明您选择了错误的模式。

【讨论】:

    猜你喜欢
    • 2011-10-31
    • 1970-01-01
    • 2012-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-26
    • 2010-12-03
    相关资源
    最近更新 更多