【问题标题】:OOP Best Practices When One Object Needs to Modify Another一个对象需要修改另一个对象时的 OOP 最佳实践
【发布时间】:2010-12-04 18:54:44
【问题描述】:

(这是一个类似 C 的环境)假设我有两个实例对象,一个汽车和一个 bodyShop。该车具有颜色 iVar 和相应的附件。 bodyShop 有一个名为“paintCar”的方法,它将接收一个汽车对象并改变它的颜色。

就实现而言,为了让 bodyShop 能够真正改变汽车对象的颜色,我看到了两种方法。

  1. 使用“&”运算符传入指向汽车的指针。然后 bodyShop 可以告诉汽车执行某种方法,它必须改变颜色,或者它可以直接使用汽车的访问器。

  2. 按值传入汽车对象,做同样的事情来改变颜色,然后让方法返回一个具有新颜色的汽车对象。然后将原来的汽车对象分配给新的汽车对象。

选项 1 对我来说似乎更直接,但我想知道它是否符合 OOP 最佳实践。一般来说,对于“最大 OOP”,“&”运算符是好还是坏?或者,也许我完全错过了一个更好的选择来制作这个超级 OOPer。请指教:)

【问题讨论】:

    标签: c oop car-analogy


    【解决方案1】:

    我会假设 bodyShop 的职责是修改汽车对象,所以#1 似乎是我的正确方法。我从未使用过需要“&”运算符的语言。通常,我的 bodyShop 对象会调用 car.setColor(newColor) ,就是这样。这样您就不必担心原车的其他属性,包括持久性问题 - 您只需不理会它们。

    【讨论】:

      【解决方案2】:

      我也同意前 1。我不能说这是最佳实践,因为我从不真正确定其他人心目中的最佳实践是什么……我可以告诉你,我心目中的最佳实践是最适用于这项工作的简单方法。我还在 hunspell win api 和其他我不得不使用的 c-ish api 中看到了这种方法。所以是的,我同意斯科特的观点。

      http://hunspell.sourceforge.net/

      //以防万一您有兴趣查看其他人的代码

      【讨论】:

        【解决方案3】:

        由于您对最佳 OOP 实践感兴趣,因此您应该忽略选项 2 对性能的影响。您应该感兴趣的唯一事情是执行任一选项都会不必要地增加两个类之间的耦合,是否违反封装并且身份被保留。

        鉴于此,选项 2 不太理想,因为您无法确定哪些其他对象持有对原车的引用,或者更糟的是,包含汽车。简而言之,您违反了身份约束,因为系统中的两个对象可能对汽车的状态有不同的想法。您冒着使整个系统不一致的风险。

        当然,您的特定环境可能会避免这种情况,但最好避免这种情况。

        最后一点,你的 bodyShop 对象是否有状态;行为和身份?我意识到您只解释了必要的最低限度,但 bodyShop 可能并不是真正的对象。


        函数式 v OO 方法

        有趣的是,选项 2 将接近函数式编程环境中的方法 - 由于不允许更改状态,因此您唯一的方法是在颜色发生变化时创建一辆新车。这不是你的建议,但很接近。

        这听起来可能有点矫枉过正,但它确实对证明代码的正确性和并行性有一些有趣的意义。

        【讨论】:

          【解决方案4】:

          选项 1 对我来说是赢家。 & 运算符隐含在许多 OO 语言(如 Java、Python 等)中。您通常不会在该语言中使用“按值传递”-仅以这种方式传递原始类型。

          选项 2 存在多个问题:您可能有一系列汽车,而某些功能不知道它可能会将汽车发送到 bodyShop 进行喷漆,作为回报收到新车并且更新你的汽车收藏。看?从更意识形态的角度来看——你不会每次在现实世界中修改它时都创建新对象——为什么要在虚拟世界中这样做呢?这会导致混乱,因为它是违反直觉的。 :-)

          【讨论】:

          • "& 运算符在许多 OO 语言(如 Java、Python 等)中是隐含的。在这些语言中您不经常使用“按值传递”——只有原始类型以这种方式传递。 "这在大多数 OOP C 中也是如此。对象通常被定义和实例化为指向结构的指针,因此您只需将未取消引用的变量名称传递给相关函数。不需要地址 (&) 或取消引用 (*) 运算符。
          【解决方案5】:

          这取决于车身车间的方法是否会失败并使汽车处于不确定状态。在这种情况下,您最好对汽车的副本或汽车的所有相关属性的副本进行操作。然后,只有当操作成功时,您才将这些值复制到汽车。因此,您最终在车身车间方法中将新车分配给旧车。正确执行此操作对于 C++ 中的异常安全是必要的,并且可以得到 nasty

          使用另一种模式也是可能的,有时也是可取的——在修改时返回一个新对象。这对于需要撤消/重做、回溯搜索的交互式系统以及任何涉及对对象系统如何随时间演变进行建模的事情都很有用。

          【讨论】:

            【解决方案6】:

            我不确定这个“类 C 环境”是什么意思。在 C 中,你需要这个:

            int paintCar(const bodyShop_t *bs, car_t *car);
            

            修改 car 指向的内容的地方。对于 C 中的大结构,您应该始终将指针而不是值传递给函数。因此,请使用解决方案 1(如果“&”是指 C 运算符)。

            【讨论】:

              【解决方案7】:

              除了其他选项之外,选项 1 让paintCar 方法返回一个完成代码,指示汽车是否已成功更改颜色或是否存在问题

              【讨论】:

                【解决方案8】:

                首选选项 1:

                bodyShop 可以告诉汽车 执行一些它必须的方法 改变颜色,或者它可以使用汽车的 直接访问者。

                更好的是...创建一个IPaintable 界面。让 Car 实现 IPaintable。让 BodyShop 依赖于 IPaintable 而不是 Car。这样做的好处是:

                • 现在 BodyShop 可以绘制任何实现 IPaintable 的东西(汽车、船、飞机、滑板车)
                • BodyShop 不再与 Car 紧密耦合。
                • BodyShop 的设计更易于测试。

                【讨论】:

                  猜你喜欢
                  • 2013-04-13
                  • 1970-01-01
                  • 2015-07-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多