流利的界面违反了得墨忒耳法吗?

Jak*_*urc 56 language-agnostic oop api-design

维基百科条目得墨忒耳定律指出:

法律可以简单地称为"仅使用一个点".

但是,一个简单流畅界面示例可能如下所示:

static void Main(string[] args)
{
   new ZRLabs.Yael.Pipeline("cat.jpg")
        .Rotate(90)
        .Watermark("Monkey")
        .RoundCorners(100, Color.Bisque)
        .Save("test.png");
}
Run Code Online (Sandbox Code Playgroud)

那么这一起呢?

Seb*_*tau 75

嗯,法律的简短定义会缩短它.真正的"法律"(实际上是关于良好API设计的建议)基本上说:只访问您自己创建的对象,或者作为参数传递给您.不要通过其他对象间接访问对象.流畅接口的方法通常返回对象本身,因此如果再次使用对象,它们不会违反法律.其他方法为您创建对象,因此也没有违规.

另请注意,"法律"仅是"经典"API的最佳实践建议.Fluent接口是一种完全不同的API设计方法,无法使用Demeter法进行评估.

  • 有人可能认为流畅的界面不违反得墨忒耳法,因为你只是访问点链中的同一个对象. (13认同)

Jon*_*jap 25

不必要."只使用一个点"是对得墨忒耳定律的不准确的总结.

当每个点代表不同对象的结果时,Demeter法则不鼓励使用多个点,例如:

  • 第一个点是从ObjectA调用的方法,返回ObjectB类型的对象
  • 下一个点是仅在ObjectB中可用的方法,返回ObjectC类型的对象
  • 下一个点是仅在ObjectC中可用的属性
  • 无限的

但是,至少在我看来,如果每个点的返回对象仍然与原始调用者的类型相同,则不会违反Demeter法则:

var List<SomeObj> list = new List<SomeObj>();
//initialize data here
return list.FindAll( i => i == someValue ).Sort( i1, i2 => i2 > i1).ToArray();
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,FindAll()和Sort()都返回与原始列表相同类型的对象.德米特法则没有被违反:该名单只与其直接的朋友交谈.

据说不是所有流利的接口都违反了得墨忒耳法则,只要它们返回与呼叫者相同的类型.


Qui*_*ome 8

是的,虽然你必须对这种情况采取一些实用主义.我总是把德米特定律作为指导而不是规则.

当然,您可能希望避免以下情况:

CurrentCustomer.Orders[0].Manufacturer.Address.Email(text);
Run Code Online (Sandbox Code Playgroud)

也许替换为:

CurrentCustomer.Orders[0].EmailManufacturer(text);
Run Code Online (Sandbox Code Playgroud)

由于我们中的更多人使用ORM,它通常将整个域作为对象图表,因此可能需要为特定对象定义可接受的"范围".也许我们应该采用demeter定律来建议你不要将整个图形映射为可达.

  • 我认为单一责任原则可能被理解为"在您的业务对象上没有方法来发送电子邮件". (3认同)

Mar*_*ade 7

Demeter定律的精神在于,给定一个对象引用或类,你应该避免访问一个多于一个子属性或方法的类的属性,因为这将紧密地耦合这两个类,这可能是无意的并且可能导致可维护性问题.

因为他们是流利接口是一个可接受的例外法意味着必须至少稍微紧密耦合,因为所有的属性和方法是被组合在一起以形成功能的句子迷你语言的条款.


And*_*nea 6

1)它根本不违反它.

代码相当于

var a = new ZRLabs.Yael.Pipeline("cat.jpg");
a = a.Rotate(90);
a = a.Watermark("Monkey");
a = a.RoundCorners(100, Color.Bisque);
a = a.Save("test.png");
Run Code Online (Sandbox Code Playgroud)

2)正如Good Ol'Phil Haack所说:得墨忒耳定律不是点数运动