声明:本文并不是博主原创,而是来自对《Laravel 4 From Apprentice to Artisan》阅读的翻译和理解,固然也不是原汁原味的翻译,能保证90%的原汁性,另外由于是理解翻译,确定会有错误的地方,欢迎指正。数据库
欢迎转载,转载请注明出处,谢谢!单元测试
在项目的整个生命周期中,绝大多数时间是在现有代码上的维护,而不是成天都在写新功能。你会意识到,这是一个让人头大的过程。任何对代码的修改,都会带来破坏原有设计,引入新bug的风险。理想状态下,咱们应是像写新代码同样,去快速简单的修改老的逻辑。若是在设计中,能正确使用开放封闭原则,就能很好的规避这些问题。测试
开放封闭原则this
SOLID设计原则中的开放封闭原则是指代码对扩展开放,对修改关闭。编码
咱们以上章中的OrderProcessor
为基础,继续来探究开放封闭原则。对于process
方法中的逻辑:翻译
$recent = $this->orders->getRecentOrderCount($order->account); if ($recent > 0) { throw new Exception('Duplicate order likely.'); }
这段代码很是好读,使用依赖注入的方法也让咱们易于测试。可是,若是针对验证的业务规则发生改编了怎么办?添加了新规则又怎么办?事实上,随着业务的发展,确定会出现_不少_新的规则!process
方法会很快的变得痈肿起来而难以维护。由于从开放封闭原则的角度考虑,他对修改是开放的,因此每当需求变动咱们都要对代码进行改变。牢记,咱们指望的是对_扩展_开放,而不是对修改开放。设计
代替掉在process
中直接使用订单验证的方式,咱们定义一个新接口OrderValidator
:code
interface OrderValidatorInterface { public function validate(Order $order); }
接下来,建立对重复订单验证的接口实现:接口
class RecentOrderValidator implements OrderValidatorInterface { public function __construct(OrderRepository $orders) { $this->orders = $orders; } public function validate(Order $order) { $recent = $this->orders->getRecentOrderCount($order->account); if ($recent > 0) { throw new Exception('Duplicate order likely.'); } } }
很好!如今一个小而可测的单独的业务规则封装类就完成了。咱们来在建立一个检测用户是否被停用的接口实现:生命周期
class SuspendedAccountValidator implememts OrderValidatorInterface { public function validate(Order $order) { if ($order->account->isSuspended()) { throw new Exception("Suspended accounts may not order.") } } }
如今咱们有了两个对接口OrderValidatorInterface
的实现类,来看看怎么在OrderValidatorInterface
中使用他们。咱们只需在订单处理类实例化时注入验证类,这样就能在原有的订单处理代码基础上轻松的添加或删除验证规则。
class OrderProcessor { public function __construct(BillerInterface $biller, OrderRepository $orders, array $validators = array()) { $this->biller = $biller; $this->orders = $orders; $this->validators = $validators; } }
接下来,只须要在process
方法中接入验证便可:
public function process(Order $order) { foreach ($this->validators as $validator) { $validator->validate($order); } // Process valid order... }
最后,咱们需要将OrderProcessor
绑定到应用程序IoC容器中:
App::bind('OrderProcessor', function() { return new OrderProcessor( App::make('BillerInterface'), App::make('OrderRepository'), array( App::make('RecentOrderValidator'), App::make('SuspendedAccountValidator'), ), ); });
这些改变,只是在原有代码上产生最小的影响,咱们如今就能不改变原来代码的基础上随便添加或者删除新的验证规则。
每一个新的验证规则只是对OrderValidatorInterface
的实现,并注入到容器中。不用对原来那种庞大臃肿的process
方法进行单元测试,如今只需单独的对新验证规则测试便可。如今代码就是对扩展_开放_,对_修改_关闭。
玉有瑕疵
要注意依赖关系的实现细节。当依赖中的实现细节改变时,用户逻辑是不该该更随着改变的。当这种状况发生时,咱们认为实现细节在以来关系中是“有漏洞的”。当抽象逻辑有漏洞,那么开闭原则也要被打破了。
在进一步处理以前,要知道开闭原则并不是硬规定。不是代码的全部地方都得支持“热插拔”。例如,那种规模很小,只是简单的获取几行MySQL数据库数据的逻辑并不需要你严格按照那些设计原则去编写代码。不要只是为了用而在编码中硬赛上这些设计原则,这反而让你的系统过分设计,变得臃肿。不少设计原则是为了解决大而复杂系统时提出的经常使用解决方案。可是,别拿这些话做为你偷懒的借口。