【问题标题】:symmetric visitor pattern对称访客模式
【发布时间】:2012-08-18 15:23:54
【问题描述】:

我正在使用访问者模式在某些类上定义一组操作。
有些操作是可交换的,所以我最终会在访问者模式代码中出现重复。
假设我有 A B C 类,并且操作:A*A、A*B、A*C、B*A、B*B、B*C、C*A、C*B、C*C。
A*A、B*B、C*C 是唯一的。
A*B、B*A和朋友会有代码重复 我可以实现 A*B,并让 B*A 调用 A*B,但我最终会问自己:我在哪个文件中再次实现了 A 和 B 之间的操作,在 A 中还是在 B 中? (大约有6个班,所以我会问这个问题很多。15对可能的操作)
将来有人在执行新操作时有可能使 A*B 调用 B*A 调用 A*B 的无限循环。
有一个约定来决定哪个应该实现 A*B 或 B*A 是不自然的。
我可以创建一个包含由 A*B 和 B*A 调用的所有已实现函数的第三个文件,这似乎不是非常面向对象的。
您将如何解决这个问题?
谢谢
(我可以列出一些代码,但它很长,不容易说明这一点)

【问题讨论】:

    标签: c++ oop design-patterns visitor-pattern


    【解决方案1】:

    你是对的,你绝对应该避免将A*B 实现为B*A 的调用。除了可能创建无限的调用链之外,这种方法不会反映代码中操作的对称性,因为代码不是对称的。

    更好的方法是在辅助类中或作为顶级函数实现“对称”操作,具体取决于您的语言支持的内容,然后让A*BB*A 调用该辅助实现.

    【讨论】:

    • 有一个指导方针,类使用其他类的属性并不完全可以。我想没有太多选择
    • Scott Meyer 在他的《更有效的 C++》一书中对这个主题进行了精彩的讨论(第 31 条:使函数相对于多个对象虚拟化。)他的例子是为一个游戏创建一个碰撞函数,其中各种物体可能在太空中发生碰撞。他的例子也是对称的(不管是小行星撞到飞船还是飞船撞到小行星,爆炸都是一样的)。他从访问者模式开始,逐渐制定出依赖于 RTTI 的 C++ 特定解决方案。
    • @titus 我很确定它是(我在 1997 年读过那本书,那本书就在那里)。
    • 我尝试用 RTTI 实现,我使用 typeid().name(),它很慢,然后我尝试为每个返回 int 的子类创建一个静态函数,这是其中之一函数指针矩阵中的索引。它仍然比访问者模式慢 3 倍。这是存储库github.com/titusnicolae/comparison/blob/master/rtti.cpp
    • @titus 这很好奇。你的函数真的很快,所以调度机制的变化导致了 3 倍的减速?
    【解决方案2】:

    我的建议是使用 builder 作为参数 Builder

    new ParameterBuilder()
        .setFirst( "A" )
        .setSecond( "B" )
        .setThird( "C" )
        ...
        .build();
    

    那么你将只有一种方法,它以ParameterBuilder 作为参数。

    【讨论】:

    • 嗯,我可以实现 Object* result = new MultiplyHelper().addOperand("A").addOperand("B").compute();
    • 我也有一些非交换函数,如 A/B,使用对称构造作为上述非对称操作是不行的。反过来更好。
    • 参数生成器仅用于获取参数,您对它们做什么取决于您。你做的也不错。我建议使用此解决方案来保持您的方法完好无损,并且只更改方法签名。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-06
    • 1970-01-01
    • 2012-04-30
    • 2013-01-18
    • 1970-01-01
    相关资源
    最近更新 更多