什么样的设计才是最好的设计?
别问,问就是自己去体会……
背景
PM同学组织了一场关于下单流程业务系统拆分的需求评审,整体功能为可线上售卖视频课,用户买完课之后可在线学习、不同的课程还包含线下实地培训等、学习完之后在线考试,颁发合格证书。
实际上,该需求可分为两个部分来看
- 售卖:通过各种渠道把各种各样的商品卖出去
- 履约:完成不同商品与之对应的履约流程
已有的实现
从上图可以清晰的看到,左侧为售卖的各种商品,右侧为商品与之对应的履约流程。
同时,每个商品对应一条独立的履约流程,商品之间可能存在相同的履约环节。
有什么问题?
有什么问题得看从什么角度看
如果从业务的角度看当然没啥问题,因为它能满足业务需求。
但是,从系统设计角度看,存在如下几个问题
- 要上架售卖新品类的商品,需要定制实现对应的履约流程
- 已有商品履约流程调整,系统也需要做对应调整
- 履约流程中的履约环节缺少复用性
业务抽象建模
从上图中,可以看出如下几个改动点
- 抽象了一个履约规则层,不同的商品对应不同的履约规则
- 由履约规则串联起商品下单与订单履约,实现下单与履约的解耦
- 订单履约模块可随意组合,以此完成履约流程
相对与之前的设计,核心变更如下所示:
有哪些好处?
通过这样的调整,好处很明显,完美的解决掉之前的问题
- 上架新品类商品,无需对应开发与之的履约流程,新增履约配置即可
- 已有商品履约流程调整,系统无需对应调整,只需修改履约配置即可
- 因为实现了解耦,下单与履约相对独立,互不影响,履约部分可提供各种各样的履约单元组合实现履约流程
聊聊面向对象设计
面向对象的四大特性
- 封装:独立模块只暴露对外接口,封装内部实现
- 抽象:例如上面抽象出来业务需求表象之下的履约规则层
- 继承:实现通用逻辑抽取,所有子类具有父类已实现的功能
- 多态:代码易扩展的利器,基于接口而不基于实现编程
面向对象的六大设计原则
- SRP 单一职责原则:每一个类、模块尽量做到职责单一
- OCP 开闭原则:对扩展开放,对修改关闭
- LSP 里式替换原则:即子类能够替换父类对象出现的任何地方,并且保证原来程序的逻辑行为不变或者说正确性不被破坏
- DIP 依赖倒置原则:高层模块不依赖低层模块,它们共同依赖同一个抽象。抽象不要依赖具体实现细节,具体实现细节依赖抽象
- ISP 接口隔离原则:意思即一个类不应该被强迫依赖它不需要的接口,即接口设计的时候不应该大而全,可做好分类,多使用接口组合
- LOD 迪米特法则:核心在于降低类的耦合;不该有直接依赖关系的类之间,不要有依赖;有依赖关系的类之间,尽量只依赖必要的接口。迪米特法则是希望减少类之间的耦合,让类越独立越好。每个类都应该少了解系统的其他部分。一旦发生变化,需要了解这一变化的类就会比较少。
其他还有
- DRY原则(Don’t Repeat Yourself)
- KISS原则(Keep It Simple and Stupid)
- YAGNI原则(You Ain’t Gonna Need It)
最后一个,我个人喜欢叫做不要加戏原则。
设计模式
设计模式更多的在于解决具体问题,我的体会是不要去套模式,多去思考怎么样去实现代码才会是最优解,当你这么做了之后,设计模式自然而然就会从你的代码里涌现出来。
几年前翻了一遍《Head first 设计模式》一书,翻完的第一感受就是原来很多设计模式在实际代码中都用过,原来每个套路还有对应的名字…
曾经整理了一个设计模式的系列文章,分别用Java与Javascript实现,在这里:
设计模式系列文章:
http://muchstudy.com/2016/12/28/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E6%80%BB%E7%BB%93/
最后
工作得越久,越会不自觉的思考,十年一线老码农相对与工作四五年的正走上轨道且精力旺盛的生力军的核,心竞争力在哪里?
可能就在于系统建模能力与面向对象设计能力上?
在于哪些东西技术上能行,而实际上坑很深,敢于有所为有所不为上?
不在于实现一个功能的快慢,而在于后续的持续迭代与维护成本上?
软件开发说简单也简单,说复杂也复杂,复杂到无法量化精确评估它的好坏!
什么样的设计才是最好的设计?
别问,问就是自己去体会……