方法链接是Martin Fowler的《领域特定语言》一书中介绍的一种技术。方法链接总结为
使修饰符方法返回宿主对象,以便可以在单个表达式中调用多个修饰符。
看这段非链接/常规代码(从上述书籍中移植到PHP)
$hardDrive = new HardDrive; $hardDrive->setCapacity(150); $hardDrive->external(); $hardDrive->setSpeed(7200);
通过方法链接,您可以以更紧凑的方式编写上述语句:
$hardDrive = (new HardDrive) ->setCapacity(150) ->external() ->setSpeed(7200);
为此,您所需要做的就是使用要链接return $this的方法:
class HardDrive { protected $isExternal = false; protected $capacity = 0; protected $speed = 0; public function external($isExternal = true) { $this->isExternal = $isExternal; return $this; // 返回当前的类实例以允许方法链接 } public function setCapacity($capacity) { $this->capacity = $capacity; return $this; // 返回当前的类实例以允许方法链接 } public function setSpeed($speed) { $this->speed = $speed; return $this; // 返回当前的类实例以允许方法链接 } }
使用方法链接的主要用例是在构建内部领域特定语言时。方法链接是表达式构建器和Fluent接口中的构建块。但是,它不是这些的同义词。方法链接仅启用这些功能。引用福勒:
我还注意到一个常见的误解-许多人似乎将流畅的界面与“方法链”等同。当然,链接是与流利的接口一起使用的常用技术,但是真正的流利性远不止于此。
话虽如此,使用方法链接只是为了避免编写宿主对象,这被许多人视为代码异味。它适用于不明显的API,尤其是在与非链接API混合使用时。
命令查询分离是Bertrand Meyer提出的设计原则。它指出,使状态发生变化的方法(命令)不应返回任何内容,而返回某些状态的方法(查询)不应使状态发生变化。这使得对系统进行推理变得更容易。方法链接违反了这一原理,因为我们正在改变状态并返回某些东西。
在使用实现方法链接的类时,在调用getter方法(即返回除之外的方法的方法)时要特别注意$this。由于getter必须返回除以外的值$this,因此将其他方法链接到getter上会使调用对获得的值进行操作,而不是对原始对象进行操作。尽管有一些链式吸气剂的用例,但它们可能会使代码的可读性降低。
上面介绍的方法链接不违反Demeter法则。它也不会影响测试。那是因为我们返回的是主机实例,而不是协作者。这是一个普遍的误解,源于人们将纯粹的方法链接与Fluent接口和Expression Builders混淆了。仅当方法链接返回除宿主对象以外的其他对象时,您才违反Demeter定律并最终在测试中出现模拟节。