设计模式(六):装饰器模式

设计模式(六):装饰器模式

这玩意玩起来很上头,打开一个总期待会有下一个,充满了趣味性

程序员在写代码时,也会遇到像套娃这样令人上头的代码

打开一个类,里面还有一个类,再打开一个,里面还有一个...

这种套娃似的代码其实是一种很常见的设计模式,它叫装饰器模式

今天我们就来扒一扒装饰器模式到底是个什么东西

实际案例

假如我们要写一个支付的功能,支付的方式有支付宝和微信

我们用代码来实现这个功能

首先我们要定义一个接口类Payment,这个接口类用来规定支付功能应该有哪些行为,也就是应该有哪些方法

比如可以有支付查询两个方法,对应的方法名分别是pay()和query()

设计模式(六):装饰器模式

然后分别定义一个支付宝类和微信类实现Payment接口类,并重写支付查询的方法

设计模式(六):装饰器模式

这样,支付功能就写好了,在需要支付的时候直接调用就可以了

比如,需要使用支付宝支付时,可以这样调用

Payment payment = new AliPayment();
payment.pay("赫连小伍测试支付宝支付");
payment.query("赫连小伍测试支付宝查询");
退款装饰器

在系统运行一段时间后,发现用户会有支付错误的情况,需要退款

这时候我们就需要新增退款功能

从实际业务考虑,退款属于整个支付功能中的一个行为。所以,应该在Payment接口类中增加退款的方法,支付宝类和微信类再分别实现这个方法

设计模式(六):装饰器模式

按照这个逻辑去修改代码,确实可以满足退款的要求,但是需要考虑一个问题

在我们的案例中只有支付宝和微信两个支付方式,真实场景中是有很多支付方式的。比如说华为支付、小米支付、云闪付、中行支付、交行支付、农行支付、工行支付等等,各种各样的支付方式加起来也有上百个

在Payment接口类上增加退款方法,意味着这上百个支付方式的类都要去实现这个方法,否则代码就编译报错

工作量太大了,耗费时间太多,项目经理不可能给研发争取这么多的时间的

我们只能想别的办法,比如可以这样去实现:再定义一个类作为支付功能的扩展类,用来扩展退款功能,命名为RefundDecorator,提供一个refund()退款方法

它既然作为支付功能的扩展类,还应该具备支付应有的功能吧,也就是说它应该有支付查询的方法,所以它应该实现Payment接口类

实现这个接口类就意味着要重写pay()和query()两个方法

重写太麻烦了,而且每个支付方式类都已经重写过这两个方法了,可以直接拿过来用。

我们把Payment类作为RefundDecorator的一个属性注入就来,这样就可以使用Payment类的pay()和query()两个方法了

在使用Payment类这个属性之前,还要给它提供一个实例化的机会

基于以上要求,我们划一下重点,RefundDecorator类的修改逻辑如下

实现Payment接口类,并重写pay()和query()两个方法

把Payment对象作为一个属性,并在构造器中对其进行实例化

设计模式(六):装饰器模式

用代码实现就是这个样子

设计模式(六):装饰器模式

修改过后,用户再使用支付宝支付功能时就可以这样调用

RefundDecorator refundDecorator = new RefundDecorator(new AliPayment());
refundDecorator.pay("赫连小伍测试支付宝支付");
refundDecorator.query("赫连小伍测试支付宝查询");
refundDecorator.refund("赫连小伍测试支付宝退款"); // 退款

其实,RefundDecorator类就是一个装饰器,这种编码方式就是装饰器模式

文章开头也说了,装饰器模式是套娃的,这里也看不出来啊

先别着急,我们再把这个案例延申一下

对账适配器

我们系统又运行了一段时间,用户既可以支付又可以退款了,用户很满意

可是,商家不满意了。因为系统每天统计的商家收入和商家的实际收入有差异,比如,昨天商家实际收入1万元,可是系统统计的只有9千元

商家对我们的系统极其不信任,要求我们必须尽快修复问题

这时候我们就需要引入对账功能,用来保证商家的实际收入和系统统计的收入数据一致

按照我们刚才添加退款功能时的逻辑来分析

不能在Payment类中增加对账方法,因为所有子类都需要重写该方法,工作量太大

只能新增一个账单类BillDecorator,里面提供一个对账方法check()

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zgwjfp.html