首页 文章

访客模式如何不违反Open Close Priniciple?

提问于
浏览
26

来自维基百科:这个想法是,一旦完成,只能修改类的实现以纠正错误;新功能或更改功能需要创建不同的类 . 该类可以通过继承重用原始类中的编码

根据我的理解,访问者模式是一种强大的技术,可以遍历使用双重调度实现相同接口的相似但不同的对象 . 在我的一个Java示例中,我创建了一组形成树结构的复合对象,这些对象的每个特定实现都实现了可访问的接口 . 访问者界面具有用于每个可访问对象的方法,并且具体访问者实现对每个这些情况执行的操作 .

我试图解决的问题是,如果我要在复合结构中添加一个也实现可访问的新实现,那么我需要重新打开访问者界面并将该情况添加到它,也迫使我修改访问者的每个实现 .

虽然这很好,但我还是需要这样做(如果访问者无法理解,那么访问者增加了什么好处?)但是在学术层面上,这不会违反开放封闭原则吗?这不是设计模式的核心原因之一吗?试图显示转换到这种模式的合理理由而不是维护switch语句来结束所有switch语句,但是每个人都认为代码将是相同的,每种情况的方法而不是交换机块,只是分解并且更难阅读 .

2 回答

  • 13

    模式适用于某些情况 . 从the GoF book(第333页):

    当定义对象结构的类很少更改时,使用访问者模式,但是您经常要在结构上定义新操作 . 更改对象结构类需要重新定义所有访问者的界面,这可能是昂贵的 . 如果对象结构类经常更改,那么在这些类中定义操作可能更好 .

    如果经常更改构成结构的对象的类,则可能难以维护Visitor类层次结构 . 在这种情况下,可能更容易在构成结构的类上定义操作 .

  • 9

    GoF之一John Vlissides在他的书中写了一篇关于这个主题的精彩章节 . 他讨论了扩展层次结构与保持访问者完整性不相容的问题 . 他的解决方案是访问者和基于类型的方法之间的混合,其中访问者被提供 visitOther 方法,该方法由"base"层次结构之外的所有类调用,访问者可以开箱即用 . 此方法为您提供了一种转义方法,可以在最终确定访问者后处理添加到层次结构中的类 .

    abstract class Visitable {
        void accept(Visitor v);
    }
    class VisitableSubclassA extends Visitable  {
        void accept(Visitor v) {
            v.visitA(this);
        }
    }
    class VisitableSubclassB extends Visitable {
        void accept(Visitor v) {
            v.visitB(this);
        }
    }
    interface Visitor {
        // The "boilerplate" visitor
        void visitB(VisitableSubclassA a);
        void visitB(VisitableSubclassB b);
        // The "escape clause" for all other types
        void visitOther(Visitable other);
    }
    

    添加此修改后,您的访问者不再违反开放 - 关闭原则,因为它可以扩展而无需修改其源代码 .

    我在几个项目中尝试了这种混合方法,并且工作得相当好 . 我的主类层次结构是在一个单独编译的库中定义的,不需要更改 . 当我添加 Visitable 的新实现时,我修改了我的 Visitor 实现,以期在它们的 visitOther 方法中使用这些新类 . 由于访问者和扩展类都位于同一个库中,因此这种方法非常有效 .

    附:还有另一篇名为Visitor Revisited的文章正是在讨论这个问题 . 作者得出结论,可以回到基于 enum 的双重调度,因为原始访问者模式与基于 enum 的调度相比没有显着改进 . 我不同意作者,因为如果你的继承层次结构的大部分是可靠的,并且期望用户在这里和那里提供一些实现,那么混合方法在可读性方面提供了显着的好处;抛弃一切是没有意义的,因为我们可以相对容易地将几个类放入层次结构中 .

相关问题