阿里P8架构师教你kill祖传石山代码重复/大量ifelse

本文就教你如何优雅消除重复代码并改变你对业务代码没技术含量的观念 。
1 crud 工程师之“痛”很多 crud 工程师抱怨业务开发没有技术含量 , 什么设计模式、高并发都用不到 , 就是堆CRUD 。 每次面试被问到“讲讲常用设计模式?” , 都只能把单例讲到精通 , 其他设计模式即使听过也只会简单说说 , 因为根本没实际用过 。对于反射、注解 , 也只是知道在框架中用的很多 , 但自己又不写框架 , 更不知道该如何使用 。

  • 设计模式是世界级软件大师在大型项目的经验所得 , 是被证实利于维护大型项目的 。
  • 反射、注解、泛型等高级特性在框架被大量使用 , 是因为框架往往需要以同一套算法应对不同数据结构 , 而这些特性可以帮助减少重复代码 , 也是利于维护 。
提升项目的可维护性是每个 coder 必须注意的 , 非常重要的一个手段就是减少代码重复 , 因为重复过多会导致:
  • 容易修改一处忘记修改另一处 , 造成Bug
  • 有一些代码并非完全重复 , 而是相似度高 , 修改这些类似的代码容易改(cv)错 , 把原本有区别的地方改成一样
2 工厂+模板方法模式 , 消除多if和重复代码2.1 需求开发购物车下单 , 对不同用户不同处理:
  • 普通用户需要收取运费 , 运费是商品价格的10% , 无商品折扣
  • VIP用户同样需要收取商品价格10%的快递费 , 但购买两件以上相同商品时 , 第三件开始享受一定折扣
  • 内部用户可以免运费 , 无商品折扣
实现三种类型的购物车业务逻辑 , 把入参Map对象(K:商品ID , V:商品数量) , 转换为出参购物车类型Cart 。
2.2 菜鸟实现
  • 购物车
  • 购物车中的商品
2.2.1 普通用户
阿里P8架构师教你kill祖传石山代码重复/大量ifelse文章插图
2.2.2 VIP用户VIP用户能享受同类商品多买的折扣 。 只需额外处理多买折扣部分 。
阿里P8架构师教你kill祖传石山代码重复/大量ifelse文章插图
2.2.3 内部用户免运费、无折扣 , 只处理商品折扣和运费时的逻辑差异 。
阿里P8架构师教你kill祖传石山代码重复/大量ifelse文章插图
三种购物车超过一半代码重复 。虽然不同类型用户计算运费和优惠的方式不同 , 但整个购物车的初始化、统计总价、总运费、总优惠和支付价格逻辑都一样 。
代码重复本身不可怕 , 可怕的是漏改或改错 。比如 , 写VIP用户购物车的同学发现商品总价计算有Bug , 不应该是把所有Item的price加在一起 , 而是应该把所有Item的price*quantity相加 。他可能只修VIP用户购物车的代码 , 漏了普通用户、内部用户的购物车中重复逻辑实现的相同Bug 。
有三个购物车 , 就需根据不同用户类型使用不同购物车 。
  • 使用多if实现不同类型用户调用不同购物车process
就只能不断增加更多的购物车类 , 写重复的购物车逻辑、写更多if逻辑吗? 当然不是 , 相同的代码应该只在一处出现!
2.3 重构秘技 - 模板方法模式可以把重复逻辑定义在抽象类 , 三个购物车只要分别实现不同部分的逻辑 。这其实就是模板方法模式 。在父类中实现购物车处理的流程模板 , 然后把需要特殊处理的留抽象方法定义 , 让子类去实现 。 由于父类逻辑无法单独工作 , 因此需要定义为抽象类 。
如下代码所示 , AbstractCart抽象类实现了购物车通用的逻辑 , 额外定义了两个抽象方法让子类去实现 。 其中 , processCouponPrice方法用于计算商品折扣 , processDeliveryPrice方法用于计算运费 。
阿里P8架构师教你kill祖传石山代码重复/大量ifelse文章插图
有抽象类 , 三个子类的实现就简单了 。
  • 普通用户的购物车NormalUserCart , 实现0优惠和10%运费
  • VIP用户的购物车VipUserCart , 直接继承NormalUserCart , 只需修改多买优惠策略
  • 内部用户购物车InternalUserCart最简单 , 直接设置0运费、0折扣
抽象类和三个子类的实现关系图
阿里P8架构师教你kill祖传石山代码重复/大量ifelse文章插图
2.4 重构秘技之工厂模式 - 消除多if既然三个购物车都叫XXXUserCart , 可将用户类型字符串拼接UserCart构成购物车Bean的名称 , 然后利用IoC容器 , 通过Bean的名称直接获取到AbstractCart , 调用其process方法即可实现通用 。
这就是工厂模式 , 借助Spring容器实现:
阿里P8架构师教你kill祖传石山代码重复/大量ifelse文章插图