与我的一个朋友又一次争吵。请考虑以下代码:
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&lt;&lt;用户。它们很容易猜到,如果我需要一些额外的功能,我可以使用has_many回调:成员并覆盖User#groups.include?在协会扩展模块中,如果有必要的话。
然而,我的朋友认为最好使用快捷方式来创建“抽象点”,最好扩展此代码而不是使用回调或重载。
你怎么想?
P.S。为了清楚起见,我讨厌“如果”的方法:)
答案 0 :(得分:2)
我完全同意不应添加这些方法。创建其他相关对象不是模型的工作。这是协会代理的工作。我还要注意重写关联代理行为,因为你可能会因代理的实现方式而看到一些奇怪的副作用。
答案 1 :(得分:1)
您引用的样式在“Demeter法则”下是可辩护的,它会警告客户端代码直接操纵groups
或members
。
答案 2 :(得分:1)
我绝对支持抽象,但不是在执行中。你的朋友提出了一个很好的观点,如果你如何确定一个成员是否在一个团体中会怎样改变怎么办?你需要进行大量的重构,祝你好运!
但是,我看到了将错误的功能放在错误的地方的论点。我说你的组织不正确,为什么不将它们附加到特定的关系模型对象?
示例:
user.groups.in_group?("admin")
或
group.members.add_user(user)
对我而言看起来更优雅,更加冗长,但你的分离更具相关性。
答案 3 :(得分:0)
对于in_group?
:您的方法名称可以在一个方向上猜测 - 当您阅读它时,它的作用非常明显。这是一种可猜测的重要方式。当某人维护此代码时,他不会被in_group?
电话跟上。它也更具说明性和简洁性,从而提高了可读性(在这种情况下略有提升,但通常也很好)。这是一种Smalltalky方法。
另一方面,我认为add_user
方法是不必要的。它似乎不是特别简洁或直接,只是非标准。这个名字仍然相当明显而且并不是非常有害,但我没有看到它的好处。它似乎更像是一条风景优美的路线,而不是捷径。
答案 4 :(得分:0)
当有原因时(例如组中的“成员”改变意义),我赞成这些方法。使用这些方法可以封装随时间增长和变化的逻辑,并有助于测试。这不是OO编程的全部意义吗?