整个代码基于接口去组织,会很自然地变得非常清晰易读 。关注实现的人才去看实现,不是嘛?
正确使用继承和组合
这也是个在业界被讨论过很久的问题,也有很多论调 。最新观点是组合的使用一般情况下比继承更为灵活,尤其是单继承的体系里,所以倾向于使用组合,否则会让子类承载很多不属于自己的职能 。
个人对此观点持保留意见,在我经历过的代码中,有一个小规律,我分析一下 。
protected abstract 这种是最值得使用继承的,父类保留扩展点,子类扩展,没什么好说的 。
protected final 这种方法,子类是只能使用不能修改实现的 。一般有两种情况:
- 抽象出主流程不能被修改的,然而一般情况下,public final更适合这个职能 。如果只是流程的一部分,需要思考这个流程的类归属,大部分变成public组合到其他类里是更合适的 。
- 父类是抽象类无法直接对外提供服务,又不希望子类修改它的行为,这种大多数情况下属于工具方法,比较适合用另一个领域对象来承载并用组合的方式来使用 。
综上所述,个人认为继承更多的是为扩展提供便利,为复用而存在的方法最好使用组合的方式 。当然,更为大的原则是明确每个方法的领域划分 。
代码复用技巧模板方法
这是我用得最多的设计模式了 。每当有两个行为类似但又不完全相同的代码段时,我总是会想到模板方法 。提取公共流程和可复用的方法到父类,保留不同的地方作为abstract方法,由不同的子类去实现 。
并在合适的时机,pull method up(复用)或者 pull method down(特殊逻辑) 。
最后,把不属于流程的、但可复用的方法,判断是不是属于基类的领域职责,再使用继承或者组合的方法,为这些方法找到合适的安家之处 。
extract method
很多复用的级别没有这么大,也许只是几行相同的逻辑被copy了好几次,何不尝试提取方法(private) 。又能明确方法行为,又能做到代码复用,何乐不为?
责任链
经常看到这样的代码,一连串类似的行为,只是数据或者行为不一样 。如一堆校验器,如果成功怎么样、失败怎么样;或者一堆对象构建器,各去构造一部分数据 。碰到这种场景,我总是喜欢定义一个通用接口,入参是完整的要校验/构造的参数,出参是成功/失败的标示或者是void 。然后有很多实现器分别实现这个接口,再用一个集合把这堆行为串起来 。最后,遍历这个集合,串行或者并行的执行每一部分的逻辑 。
这样做的好处是:
- 很多通用的代码可以在责任链原子对象的基类里实现;
- 代码清晰,开闭原则,每当有新的行为产生的时候,只需要定义行的实现类并添加到集合里即可;
- 为并行提供了基础 。
集合是个有意思的东西,本质上它是个容器,但由于泛型的存在,它变成了可以承载所有对象的容器 。很多非集合的类,我们可以定义清楚他们的边界和行为划分,但是装进集合里,它们却都变成了一个样子 。不停地有代码,各种循环集合,做一些相似的操作 。
其实很多时候,可以把对集合的操作显示地封装起来,让它变得更有血有肉 。
例如一个Map,它可能表示一个配制、一个缓存等等 。如果所有的操作都是直接操作Map,那么它的行为就没有任何语义 。第一,读起来就必须要深入细节;第二,如果想从获取配置读取缓存的地方加个通用的逻辑,例如打个log什么的,你可以想象是多么的崩溃 。
个人提倡的做法是,对于有明确语义的集合的一些操作,尤其是全局的集合或者被经常使用的集合,做一些封装和抽象,如把Map封装成一个Cache类或者一个config类,再提供GetFromCache这样的方法 。
经验总结本文从clean code的几个大前提出发,然后提出了实践clean code的一些手段,重点放在促成clean code的一些常用编码和重构技巧 。
当然,这些只代表笔者本人的一点点感悟 。好的代码,最最需要的,还是大家不断追求卓越的精神 。欢迎大家一起探索交流这个领域,为clean code提供更多好的思路与方法 。
侵权提醒必删
【美团:怎样写出漂亮整洁的代码?聊聊clean code的编码、重构技巧】
推荐阅读
- 你们说的抖音效果是怎样实现的!程序员:java面前都不是事
- 脚趾扭伤怎样消肿
- 怎样护理卧床老人?需注意四方面
- 花呗延期还款是否影响征信 花呗延期还款会怎样
- 淘宝特价版怎样发布商品 淘宝特价版有什么活动
- 文件怎样加盖骑缝章盖? 如何盖骑缝章
- 红茶可以收藏吗 红茶要怎样保存
- 怎样把两段录音合并在一起 手机上录音怎么配音乐
- 红茶存储,日常家庭中怎样保存红茶
- 怎样识别金俊眉红茶的真假多种方法与您分享