1

又是和我的一个朋友争吵。考虑这段代码:

class User < ActiveRecord::Base
  has_many :groups
  def in_group?(group)
      groups.include?(group)
  end
end
class Group < ActiveRecord::Base
  has_many :members
  def add_user(user)
      members << user
  end
end

我的观点是这些方法给代码增加了额外不必要的复杂性,而且很难猜到——比如为什么要#in_group?但不是#is_a_member_of?,或者为什么是#add_user 而不是#add_member,等等。基于我 4 年的 Rails 经验和 20 年的编程经验,我最好遵循 AR 语义并使用 User#groups.include?(group) 和 Group#members << user. 它们很容易猜到,如果我需要一些额外的功能,我可以对 has_many :members 使用回调并覆盖 User#groups.include? 如果有必要,在关联扩展模块中。

然而我的朋友认为最好使用快捷方式来创建“抽象点”,并且最好扩展此代码而不是使用回调或重载。

你怎么看?

PS为了清楚起见,我讨厌“如果”的方法:)

4

5 回答 5

2

我完全同意不应该添加这些方法。创建其他相关对象不是模型的工作。这就是关联代理的工作。我还要提防覆盖关联代理行为,因为由于代理的实现方式,您可能会看到一些奇怪的副作用。

于 2009-02-08T18:35:21.370 回答
1

您引用的样式在“得墨忒耳法则”下是可以辩护的,该法则警告不要直接groupsmembers直接操作客户端代码。

于 2009-02-08T18:50:50.620 回答
1

我绝对赞成抽象,但不赞成这种执行。你的朋友提出了一个很好的观点,如果你确定一个成员是否在一个组中的方式会发生变化怎么办?你有大量的重构工作要做​​,祝你好运!

但是,我看到了将令人困惑的函数放在错误的地方的论点。我会说您的组织不正确,为什么不将它们附加到特定的关系模型对象?

例子:

user.groups.in_group?("admin")

或者

group.members.add_user(user)

对我来说,这看起来更优雅,更冗长,但你的分离更相关。

于 2009-02-08T18:55:52.077 回答
0

For in_group?:您的方法名称在一个方向上是可以猜到的——当您阅读它时,它的作用非常明显。这是一种重要的可猜测性。当有人在维护这段代码时,他不会赶上in_group?电话。它也更具声明性和简洁性,从而提高了可读性(在这种情况下很少,但通常很好)。这是一种 Smalltalky 的方法。

另一方面,我认为这种add_user方法是不必要的。它似乎并不特别简洁或直接,只是不标准。这个名字仍然相当明显并且没有严重的危害,但我看不出它有什么好处。这似乎更像是一条风景优美的路线,而不是一条捷径。

于 2009-02-08T18:44:00.663 回答
0

当有原因时(例如成为一个组中的“成员”改变了含义),我赞成这些方法。拥有这些方法封装了会随着时间而增长和变化的逻辑,并且确实有助于测试。这不是面向对象编程的重点吗?

于 2009-02-08T22:50:54.560 回答