最近在为公司商城做第三方支付对接。看了之前的微信支付,感觉和之前看到的设计模式结合了。我想看看能不能用上面的Use。研究了一番,觉得还可以,但可能有点坑爹。Patterndefinitionstrategypatterndefinitionstrategy模式定义了算法族,单独封装,使得它们可以相互替换,这种模式使得算法的改变与使用算法的客户端无关。模板方法模式定义模板方法模式定义方法中算法的骨架,将一些步骤推迟到子类。模板方法使得子类可以在不改变算法结构的情况下重新定义算法中的一些步骤。ROUND1:多种支付方式1.场景描述微信支付有预购、退款、订单查询等接口,看了第三方支付,也是类似的。很简单,我们会想到下面的类图:图中我们可以看到WxPay和SandPay都继承了Pay,它们的行为是一样的:下单、退款、查询订单,但是我们可以知道它们的实现是肯定不一样,我们必须重写父类的方法来处理不同支付的细节。这样的话,代码就会显得冗余,每个子类都需要重写父类的实现。如何让代码更统一?2、问题分析这时候,我们需要的是将行为分离出来,封装在一个具体的行为类中,这样我们就可以将行为“指定”到支付实例中。比如我们要生成一个新的第三方支付实例,我们可以动态启用它来下单微信支付(当然这是不合理的)。这时候我们使用了一个很重要的设计原则:对于接口编程,而不是对于实现编程,我们用接口来表示每一个行为,比如OrderBehavior和RefundBehavior,每一个行为的实现就是实现其中一个接口。支付类没有实现下单和退款的接口,有其他类具体实现。我们称这个类为“行为”类。与前面的做法不同的是,前面的做法是:行为由接口的超类或子类继承,并由自己实现。这两种方法都依赖于“实现”,所以我们很容易被实现所束缚,以后很难改变行为(除非编写更多代码)。在新的设计中,支付类将使用接口所代表的行为,因此实际的“实现”不会绑定支付类,这样支付类就不需要了解行为实现的细节。看看新的类图:还有,看看Pay抽象类中的统一方法代码:orderBehavior->orderPay();}publicfunctionrefund(){return$this->refundBehavior->refund();}}然后在实现的时候,子类可以动态实现这个orderBehavior=newWxOrder();//实现微信支付订单$pay->orderPay();//第三方支付同理$pay=newSandPay();$pay->orderBehavior=newSandOrder();$pay->orderPay();可能这时候有人会问了,我直接在具体的类中实现这个方法就可以了,不需要写那么多类和接口,正常情况下支付不会改变它的实现。是的,一般来说支付是不会修改的,但是如果突然说现在没有第三方支付了,所有的支付都是微信支付,那么我们的代码可能会修改很多,但是有了这个实现我们只需要改一个小地方:orderBehavior=newWxOrder();//因为我们不需要担心实际的细节,所以我们不需要做太多的代码更改,我们可以有把握地说代码中不会有错误$pay->orderPay();实现方式也符合一个设计原则:多用组合,少用继承。实际的实现不是通过继承得到的,而是通过其他类的组合得到的。不仅可以将算法族封装成一个类,甚至可以“在运行时动态改变行为”,只要行为对象符合正确的接口标准即可。在这种情况下,您认为使用了哪种设计模式?ROUND2:相同的实现结构1.场景描述在处理了多个支付场景后,我们在最开始添加了第三方支付代码。在编写过程中,我们发现下单操作类似于微信支付。我们需要在请求之前,组装请求的必要参数和签名,得到返回结果后,验证数据的签名,然后执行自己的业务逻辑,最后返回响应。同理,退款操作也是一样:拼装请求、签名等必要参数,与订单操作逻辑的顺序或结构几乎相似。如果我们继续这样写,我们会发现很多重复的代码。这时候怎么处理毛呢布?2.问题分析在解决问题之前,先说一个重要的设计原则:找出应用中可能需要改动的地方,将它们分开,不要和不需要的代码混在一起变了。通俗地说,就是要善于发现现实中的变化和不变,把不变的地方抽取出来让其复用,然后让变化的部分自己去解决。在这种情况下,它非常特殊。我们发现不管是微信订退,还是第三方订退,他们的业务逻辑几乎是一条流水线,这是他们不变的。发生了什么变化?显然,业务的具体实现是不同的,这部分应该由业务自己来实现。这样,我们用类图来表示描述如下:代码如下:$this->generateSign();$this->请求();$this->verifiedSign();$this->handleResponse();$this->returnMsg();}抽象保护函数generateRequestData();抽象保护函数generateSign();受保护的函数handleResponse();抽象保护函数verifiedSign();抽象保护函数returnMsg();}classWxOrderextendsPayAction{publicfunctionorderPay(){$this->doAction();}}只是对于这一系列的操作,我们可以这样写,这样所有的行为都是一样的,只需要自己去实现不同。ROUND3:组合效果1.如果把第一种情况的结构和第二种情况的结构结合起来,最后会是什么样子?我们可以看一下:这样,整个结构就很清晰了。客户端调用行为的订单或退款类实现,不知道具体细节,行为的对象可以动态改变;而提取行为操作中重复的部分,只需要单独实现变化的部分,不变的部分先由抽象类PayAction定义,然后公共部分由不同的支付类实现:signature和验证,甚至返回正确和错误时的最终固定格式是同一笔付款中的同一部分;finally的区别只是请求次数不同,请求参数不同,获取到返回参数后的处理不同。类和接口确实比原来的设计多了很多,但是结构很清晰,修改的时候可以有针对性的修改。对于客户端来说,调用是透明的。对于提供服务的我们来说,不管是新的支付方式,还是额外的支付操作,我们都可以在不修改已有代码的情况下,很好的添加代码,而这也是经常被提及的一个设计原则:开闭原则:closedformodification,OpentoextensionsROUND4:Answersandcomparisons第一和第二个场景,它们对应的设计模式是什么?第一种设计模式是:策略模式,第二种是:模板方法模式。首先我们可以清楚地看到,当我们要运行一个行为时,我们将它封装在一个类中,并且,它们可以相互替换。算法更改由客户决定,可以动态更改。第二个我们看到的是整个算法的结构已经定义好了,我们可以按照预定的模板来写我们的算法来实现类似的功能并且写得井井有条,没有多余的部分,可以专心处理你的自己特殊的业务逻辑。因此,以后如果代码的相关结构非常相似,可以选择模板方法模式来编写;如果业务中有些行为可以抽象出来,需要动态改变,可以考虑策略模式来写。
