来自维基百科的定义
更正式地说,函数的得墨忒耳定律要求对象 O 的方法 m 只能调用以下类型对象的方法
1. O itself
2. m's parameters
3. Any objects created/instantiated within m
4. O's direct component objects
5. A global variable, accessible by O, in the scope of m
特别是,一个对象应该避免调用另一个方法返回的成员对象的方法。对于许多使用点作为字段标识符的现代面向对象语言,该法则可以简单地表述为“仅使用一个点”。也就是说,代码 abMethod() 违反了 a.Method() 没有的规律。举个简单的例子,想要狗走路时,不会直接命令狗的腿走路;取而代之的是命令狗,然后狗命令自己的腿。
在上述情况下,是的,这将违反得墨忒耳定律:
def first_survey?
# Should this be broken according to Law of Demeter?
self.kingdom.surveys.count == 1
至于它是否矫枉过正,我说不,但我不喜欢糟糕的代码(即不正确的代码,允许的错误多于应有的错误,我对此有很多争论)。
你想要做的是这样的:
def first_survey?
self.kingdom.surveys_count == 1
如果我的理解是正确的,这并不违反 Demeter,因为您没有suverys.count
直接访问该属性。相反,您要求kingdom
返回它拥有的内部属性(我认为这更正确,因为它正在使用对象的 API kingdom
)
# Is this the "right thing to do", or overkill?
def surveys_count
self.surveys.count
end
这是“正确的做法”,否则外部系统将如何访问该属性?
从评论中
只使用一个点实际上是一个非常糟糕的规则,因为 "string".strip.downcase.tr_s('^[a-z0-9]', '-') 不违反 demeter
好吧,既然你提出来了,我会反驳你的说法。这实际上不是一个坏规则,因为您在这里忽略了一条非常关键的信息,strip 函数返回一个新的字符串对象以及 tr_s 的小写。如果您要生成三个额外的对象,我会非常担心任何看到这一点的开发人员。它确实违反了规则,因为您正在直接访问成员。你想要考虑的,我绝不是 Ruby 专家,是这样的:
class MyString
{
string internal_string;
def strip()
{
self.internal_string = self.internal_string.strip
}
def downcase()
{
self.internal_string = self.internal_string.downcase
}
def tr_s()
{
self.internal_string = self.internal_string.tr_s
}
}
上面所做的是允许开发人员通过在库函数周围放置一个瘦包装器来调用您的 API。有些人可能会称之为矫枉过正,但它对可以做什么和应该做什么给出了非常明确的界限。现在让这个得墨忒耳得到批准(如果我正确理解法律的话)
myString.strip().downcase().tr_s()
现在可能不清楚的是,这并不违反 Demeter,因为我正在调用公开的 API myString
,过度杀伤(也许),最正确(几乎肯定)。