流畅接口是否违反了迪米特法则?

62

维基百科文章关于德米特法则的介绍如下:

该法则简单地表述为“仅使用一个点”。

然而,一个流畅接口简单示例可能看起来像这样:

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

所以这些东西是配套的吗?


1
这是一个重要的问题,因为违反Demeter法则可能会使包含模拟的单元测试难以维护(尽管流畅的链可能是一个例外)。 - Sridhar Sarnobat
7个回答

90

嗯,对于该法则的简短定义过于简单了。实际上,“法则”(实际上是有关良好API设计建议)基本上是这样说的:只访问您自己创建的对象或作为参数传递给您的对象。不要通过其他对象间接访问对象。流畅接口的方法通常返回对象本身,因此,如果再次使用对象,则不违反该法律。其他方法为您创建对象,因此也没有任何违规行为。

另外,请注意,“法则”仅是“传统”API的最佳实践建议。 流畅接口是API设计的完全不同的方法,不能使用Demeter法则进行评估。


16
有人认为流畅接口并不违反迪米特法则,因为你在点链中只访问同一个对象。 - MSN
1
另一种看待这个问题的方式是,流畅接口只是一种替代的、紧凑的方法,用于以抽象状态变化的方式执行序列操作,因为每个中间步骤的结果都是隐含的。 - Kenogu Labz

28

不一定。"只使用一个点"是对迪米特法则的不准确概括。

迪米特法则不鼓励在每个点表示不同对象的结果时使用多个点,例如:

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

然而,在我看来,如果每个点的返回对象仍为原始调用者的相同类型,则不会违反迪米特法则:

var List<SomeObj> list = new List<SomeObj>();
//initialize data here
return list.FindAll( i => i == someValue ).Sort( i1, i2 => i2 > i1).ToArray();
在上面的示例中,FindAll()和Sort()都返回与原始列表相同类型的对象。迪米特法则并没有被违反:列表只与其直接关联的对象交互。
话虽如此,并非所有流畅接口都会违反迪米特法则,只要它们返回与调用者相同的类型即可。

9

Demeter法则的精神是,针对一个对象引用或类,应该避免访问超过一个子属性或方法的类的属性,因为这将紧密耦合两个类,这可能是不想要的并且会导致可维护性问题。

流畅接口是该法则的可接受例外,因为它们旨在至少有些紧密耦合,因为所有属性和方法都是一种迷你语言的术语,这些术语组合在一起形成功能句子。


8

是的,虽然你需要对情况采取一些实用主义。我总是将Demeter法则作为指导方针而不是规则。

当然,你可能会想避免以下情况:

CurrentCustomer.Orders[0].Manufacturer.Address.Email(text);

也许可以替换为:

CurrentCustomer.Orders[0].EmailManufacturer(text);

随着越来越多的人使用ORM,通常将整个域表示为对象图,因此定义特定对象的可接受“范围”可能是一个好主意。也许我们应该遵循洛德米特法则,建议您不应将整个图形映射为可达。

4
我认为单一职责原则可能被理解为“不要在您的业务对象上拥有一个发送电子邮件的方法”。 - Mark Rendle

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");

2) 正如Phil Haack所说:迪米特法则不是一个点计数的练习


1

你的例子没有问题。毕竟,你一直在旋转、加水印等操作同一张图片。我相信你一直在与 Pipeline 对象交互,只要你的代码仅依赖于 Pipeline 类,就不会违反 LoD 原则。


1

实际上,一个对象不应该暴露其内部(数据),而是应该暴露用于操作内部的函数。

考虑到这一点,流畅的API要求对象使用其数据来处理某些内容,而不是请求数据本身。

这并不违反任何迪米特法则。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接