1

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

至于实现,为了让 bodyShop 实际上能够改变汽车对象的颜色,我看到了两种方法。

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

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

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

4

8 回答 8

5

选项 1 是首选:

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

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

  • 现在 BodyShop 可以绘制任何实现 IPaintable 的东西(汽车、船、飞机、滑板车)
  • BodyShop 不再与 Car 紧密耦合。
  • BodyShop 具有更可测试的设计。
于 2009-10-08T20:54:53.887 回答
3

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

于 2009-10-07T21:16:40.437 回答
2

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

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

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

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


功能性 v OO 方法

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

这听起来像是完全矫枉过正,但它确实对证明代码的正确性和并行性有一些有趣的影响。

于 2009-10-07T21:25:36.000 回答
1

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

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

于 2009-10-07T21:42:51.220 回答
1

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

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

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

于 2009-10-07T22:51:54.457 回答
0

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

于 2009-10-08T13:11:04.837 回答
0

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

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

于 2009-10-07T21:58:31.153 回答
0

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

http://hunspell.sourceforge.net/

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

于 2009-10-07T21:22:14.827 回答