
本文共 1900 字,大约阅读时间需要 6 分钟。
【大话设计模式】-- 策略者模式(Strategy):它定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变法,不会影响到使用算法的客户。
策略模式的核心就是屏蔽内部策略算法,内部的算法是可以随时替换,对外部是没有感知的。若新增或修改内部的算法,只需要修改或者扩展相应的策略类,客户端的代码无需改动,符合设计模式中一个重要的原则:开闭原则。
一. 业务需求背景
1.需求目的:
用户可以进行对某种配置进行预约,到达配置的预约时间点,根据Redis队列的预约号执行预约,不同类型的配置预约操作逻辑完全不同。2.流程图:二. 使用策略模式的缘由
此业务由于是要支持不同配置的预约,以及后期可能会有很多种类型的配置,而且不同类型的配置又完成不同,如果直接编码,后期的扩展性以及维护性会比较麻烦。
1.正常代码实现:reservationAConfig($mainkey); break; case 'B': $this->reservationBConfig($mainkey); break; ..... } } private function reservationAConfig($mainkey){ //这里进行A配置的预约逻辑操作 } private function reservationBConfig($mainkey){ //这里进行B配置的预约逻辑操作 } private function getReservationTypeByMainkey($mainkey){ //根据预约号获取预约配置的类型 }
这样子的实现也是可以满足业务需求,代码的可读性也还好。但是会有一个问题,这种预约的配置种类会很多,会导致switch的语句会越来越多,也可能会修改一些预约配置逻辑。这样子的话就需要修改原来的代码,对于代码质量来说,这并不是一种好的现象。
2.策略模式实现
$strategy = $strategy; } //封装了策略执行的逻辑,所有执行的预约配置统一调用这个方法 public function makeReservation(){ $this->$strategy->makeReservation(); }}//A配置的具体策略类class AReservationStrategy implements ReservationStrategy{ public function makeReservation(){ //这里执行A配置的逻辑操作 ;}class ReservationFacaory{ public static function getReservationInstance($mainkey){ //这里可以根据预约号做具体逻辑生成策略对象 }}//预约控制器代码class ReservationController{ public function makeReservation($mainkey){ //根据工厂对象创建预约策略实例 $reservation = ReservationFacaory::getReservationInstance($mainkey); //传入实例给策略处理类 $handler = new ReservationHandler($reservation); //执行预约策略 $handler->makeReservation(); }}
以上代码使用了工厂模式以及策略模式的结合,其中ReservationHandler类作为处理上下文的类,通过依赖注入相应的策略类,直接调用makeReservation方法。在客户端代码只需要调用此方法即可,即使后期预约逻辑也无需改动客户端的代码。在此业务需求,因为需求并不是很大,所以工厂类只是简单实现。如果想要更完善,工厂类根据反射机制以及约定好的类名动态生成实例,这样后期如果扩展类型,只需要实现相应的接口即可,无需改动其他代码,很方便扩展。
总结
实践才能出真知。以前看大话设计模式这本书,总觉得自己看了好多遍但是还是云里雾里的,不知道为什么需要这种代码结构。但是通过一个小需求设计这么一个结构,我很快就能get到这种结构带来的好处。虽然在这个业务上,这种结构的优势并没有特别的明显,甚至可能有点增加代码量,但是我相信在后期扩展以及维护方便是有很大的好处的。记录这篇文章,主要是想要记录自己的思考方式以及学习体会,如果有一些不太对的地方欢迎大家指正,一起进步!!