我想分享一个我最喜欢的、屡试不爽的设计模式——“管道模式”。所谓的“管道模式”,可以将其想象成一个“传输带”,或者“生产线”,它们传递一个东西,每一步进行相应操作,然后再传给下一环。在编程里,就是拿起一个实例对象,进行必要操作或修改,然后再传给下一个类,如此传下去。
可以想象这么一个订单处理的电商逻辑:
- 用户下单了
- 支付逻辑处理了支付
- 订单记录,或者发货单生成了,并发送给了用户
- 订单发送到了你的ERP系统中了,交付生产了
- 订单物品打包后发货了
- 用户收到了一封感谢信
虽然借助于某些状态机(state-machine,可大致理解成管理状态的机器系统),这整个流程会更好处理些,但是这期间,很显然展示出了一个“管道”、“流程”或“步骤”概念。
在这些所有的步骤或管道中,有一个基本的常量——这个订单,它被传递到了这个过程的每一步,直到最后处理完。
如果你之前搞过类似的逻辑,那么十有八九你会在你的比如说Order.php
里,搞类似的这么一堆乱糟糟的代码:
if ($order->getStatus() === 'success') {
$this->getErpAdapter()->sendOrder($order);
}
// 此处省略了一百个if判断
这样的代码,要理解它,你就得一行行的紧盯着看,又乱又费时间,让人没心情看完。
Any fool can write code that a computer can understand. Good programmers write code that humans can understand.
任何一个傻子,都可以写出能让计算机执行的代码;但是只有好的程序员,才能写出让人看得懂的代码。
——Martin Fowler
这是我喜欢的一个引用。那么现在,看看下面的代码:
$pipeline = (new Pipeline)
->pipe(new createOrder)
->pipe(new processPayment)
->pipe(new sendInvoice)
->pipe(new exportOrder);
$pipeline->process($order);
现在还会有人抱怨“可读性”吗?不会了吧。
这样来写,同样也让你在“可测试性”上,以及单一职责原则上,获得巨大胜利——因为你现在每一块代码只做一件事儿,或者相关的两件也行,然后就传给下一个类了,职责非常简单清晰。这样整个流程的每一步都是可测试的,都可以轻易mock,甚至整个的管道流程也是可测试的。
好了,由于本文较长,剩下的请移步我们原文发布处阅读,以下是剩下的目录结构