`return $this;` 设计模式还是反模式?

14

我经常看到Zend Framework使用return $this;的链式调用风格 - 从我的角度来看:

  • 优点:这种风格似乎是不错的,可以在同一个对象上链接多个操作并使代码更简洁。

  • 缺点:当你看到对象返回自身的方法执行其他操作时(例如某个属性的setter方法),代码看起来有些奇怪。

这是真正的良好实践还是反模式?

编辑: 我过于夸大其辞地将其称为 "模式",谢谢大家指正!


11
请参考Martin Fowler有关“流畅接口”的文章(http://martinfowler.com/bliki/FluentInterface.html)。我从未将其视为反模式。它对许多事情非常有效。jQuery是另一个著名的流畅接口。 - BoltClock
这只是一种编码风格和语法糖,而不是一种模式。 - OZ_
5个回答

10

返回 this 允许你链接调用并设置值。它非常适用于配置某个对象(参见流畅接口)。你可以非常轻松地表达你想要什么(并且你可以使用不同的返回类型来实现你想要的功能)。


8

我发现方法链在某些情况下非常有用,比如在特定领域的语言中:

$query->select('*')->from('users')->where(array('user_id' => 1, 'verified' => 1));

事实上,这些方法只会返回void,因此return $this仅仅是写成这样的简写形式:
$query->select('*'); $query->from('users'); $query->where(...);

我们仍将调用 toSQL()execute() 方法来利用我们填充对象的数据。

在我看来,这不是一种反模式,并且在正确的情况下可以作为一种合法、明智的对象填充方法。


7
如果你的意思是“好的实践或坏的实践”,那么这是我的看法:
优点是,你能够得到一些语法糖。
缺点是,你放弃了有意义的返回值,以换取可链接性。这并不是可行的,因为最终你必须要有那些返回基本对象之外的方法,所以你最终会有一些可链接和一些不可链接的方法(使用者需要猜测哪些是哪些)。
否则,你就必须让它们全部都可链接起来,但是接下来你将遇到一些荒谬的情况,比如为了保留链条而返回一个虚假的“空”对象,这个对象需要检查一些晦涩的属性才能确定它是否是“真正”的对象还是链中的链接。
经典例子是jQuery,它展示了所有的症状:基本对象试图成为整个代码中唯一的基本数据单元(一切都返回一个jQuery对象);虚假对象测试(if (obj.length));另外还有一个自相矛盾的问题,即它仍然需要打破可链接性,比如对于返回字符串的getAttribute()等方法。
在我看来,仅仅为了那一点点的语法糖,把事情搞得一团糟是非常可怕的。

旁注:这种方法在使用jQuery时会导致不自然和不良的实践。例如,你在#foo下查找具有.bar类的元素,但是你没有找到任何元素,甚至没有找到#foo。大多数情况下,这意味着你有一个大问题,它们很可能应该在那里。你不在乎它们是否存在的情况非常罕见。然而,jQuery鼓励你忽略#foo或.bar缺失的事实,并让你愉快地链接将什么也不完成的方法,而没有任何警告。这扭转了事情的本质,它把一个更小的用例变成了规范。 - Dave May
我认为你说得很对。也许你可以通过使用不同的类来分离可链式方法和不可链式方法,从而兼顾两者,就像我在这里尝试演示的那样:http://blog.programster.org/fluent-interface/ - Programster

3

3
这并不是PHP/Zend Framework的专属功能,因为许多其他编程语言也使用了流畅接口。我认为使用流畅接口非常方便,是一种很好的编码方式。尽管有时代码看起来很奇怪,但并不意味着它是错误的,坦率地说我不认为你可以将其归为缺点。

最终,程序员只看到他得到了相同的对象,而不是流畅接口类代码内部的样子。我认为流畅接口最大的优点是代码可读性。如果您想听到一个缺点,那就是调试流畅链可能比较困难。


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