在不修改原始源代码的情况下扩展访问者模式?

时间:2014-10-10 13:59:36

标签: java design-patterns visitor extensibility

我有一个问题是在多个模块中扩展访客模式,您可以在评论中阅读问题的解释。

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中 没有这样的问题,但我认为这也不是完美的方式。

问题是我们可以通过访问者做得更好吗?

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

1 个答案:

答案 0 :(得分:1)

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

“改变的原因”全部分为两大类:数据和功能。访问者模式将数据和功能之间的正常OO直接关联分离,使您能够牺牲更改数据结构的能力,以便能够非常轻松地更改功能。添加另一个ISourceVisitor是微不足道的,因为访问者模式的目的就是让你这样做。添加另一个ISource会更改您的数据结构并强制您更改所有功能以适应它,这肯定表明您选择了错误的模式。