首页 昆明信息港 下载客户端 关于彩龙 论坛须知

一个“BUG”引发的血案:从“解藕”出发谈谈代码质量的改进

请原谅我是标题党!^_^

四月初入港。进入咱们大家庭后第一感受是:工作氛围轻松活泼,同事相处融洽和谐。

经过近一个月工作,对现有的业务代码形态也有了一定认识,除了对以往开发人员的刻苦努力和认真负责感到敬佩之外,也发现了一些以往累积的问题。

由于涉及到业务核心逻辑,这里不展示相关业务代码,仅仅从“解藕”这个出发点,谈谈个人对开发的理解,如有错误及不足之处,恳请亲们不吝指正。

相信很多开发人员都听说过“六大原则”,又称设计模式六大原则,面向对象编程六大原则,以及函数化编程等各类流行说法。但无论如何,这些原则、方法,在某种层面上或者角度来看,其实是在要求我们做一个事情:解藕。

什么是解藕?

简单的说就是,去依赖或者最小化依赖。在限定业务场景下,最大化的消除对象之间的依赖性和最大化提高业务的内聚性。更直白的说法就是,对业务进行抽象,对抽象后的业务进行分层、分模块、分包设计,以实现更好的可移植性和可修改性和可维护性。

对于绝大多数的项目而言,可维护性又是我们最关注的。因为在产品迭代的过程中,或多或少我们都需要面对这样一个事实:开发人员不在,当前项目如何继续推进?开发人员不在的情况可以是,请假了;离职了;或者突发BUG,需要紧急处理维护,而开发人员无法到场处理。

而这个时候,项目的可维护性就直观的表现为:“非专业”人员能否快速介入解决“专业问题”。简单的解释就是,一个新手能否快速掌握项目业务,接上之前欠下的开发。新的开发者会不会因为前任埋下的漏洞和四处填坑,心力交瘁?

这反向的说明,项目可维护性的重要性,代码质量的重要性。

那我们现在来谈谈,如何提高代码质量,如何进行代码解藕,我们先来重复一下六大原则的内容:

单一职责原则;

里氏替换原则;

依赖倒置原则;

接口隔离原则;

迪米特法则;

开闭原则;


六大原则从不同的角度、纬度说明了一些解藕的方法,提高代码质量的方法。

单一职责的目的是降低代码复杂度,增加代码的可读性和可维护性,减少逻辑上的“误导”。

里氏替换的意思可以简单的说成:爹能干的事,儿子一定能干。其实也是对原则六的一个侧向说明,即,子类不能改变父类方法的输出类型,但是可以创建自己内部行为。简单的说就是,这个方法必须返回“6”,父类是“3+3=6”,子类是“2*3=6”。

依赖倒置的另一种表述就是面向接口编程,简单的说就是,两个类的相互依赖于对方所实现接口,换言之,没有类之间的相互依赖,有的只是接口依赖。事实上,这种完美的接口依赖是很难实现的,或者无法实现的,因为,最终处理业务的是类本身,而不是接口。

接口隔离原则,简单的就是类本身不应该也不能实现不需要的接口,这可以确保我们不会开发出让其他开发人员代码阅读者困惑的代码。当然,如果你要报复别人或者是抹黑自己,这不失为一个好方法(开玩笑...)。

迪米特法则,又成为最少知识原则。简单说,我们要最小化的降低类之间依赖。这样当一个类变化的时候,依赖他的类会受到最小的影响,而最小的影响即体现为,这次修改需要修改一百个文件和只修改一个文件的区别。

开闭原则:简单的说就是,尽量少改原来的东西,需要变化的时候我们扩展他。

方法论总结:我们在开发过程中需要做的是,梳理类的依赖结构,梳理类的职能划分,进而进行有效的设计。这在很大程度上可以确保代码设计符合六大原则。直白的说,开发之前先设计是非常必要的,这对提高代码质量非常有效。

由上面的表述我们可以知道,“依赖性”管理是解藕的最基础操作。抛开那么多理论的东西,我们来讨论一下如何合理的设计依赖:

假设有类A,类B,类C,其中,类A中需要初始化一个类B的对象,类B中需要初始化一个类C对象,类C中会持有一个类A的实例。问,如何初始化这些类?

A->B->C->A

我们设定了一个相互循环嵌套的依赖关系,如果加上一个限制条件:每个类在创建的时候都需要传入所依赖的类的实例,如何实现?

··························

··························

这是漫长而随意的分割线,以方便大家思考两秒钟

····························

····························

·····························

································

·····························

·······························

揭秘答案,答案是无法实现。这已经构成了一个无限循环嵌套,简单写一个伪代码来验证一下答案:

new A(new B(new C(new A(new B(new C(new A(...)))))))

很显然,直到世界的尽头,我们也没法实例化这样的类。

那是否我们就没有办法实例化对象了?当然不是,上面的说法在某种现实层面上看,算是个伪命题。完全不会存在两个实例化时需要对方实例的类,也完全不会存在相互依赖关系完全一致的两个类。也就是说,我们总是可以先创建A然后再创建B。所以处理依赖性的时候,我们需要考虑一个问题:依赖注入的时机!简单的说就是,我需要在A对象中使用一个B对象,那么在A对象中实例化B对象最佳时机的问题。这里有一个最简单的方法是,最近使用最近创建,即在使用之前的“最后一刻”创建对象,这“一刻”很有禅学或者玄学的味道,还是需要开发人员慢慢体会。这种最后一刻所带来的好处是尽量的降低了依赖的“副作用”(提前长期持有并不需要的对象,对于面向对象编程本身也是一种负担)。

闲篇扯了这么多,本文就介绍到这里吧!

本文原创发布在“彩龙社区”,如需转载请注明出处!


网友评论

7条评论

发表

网友评论

7条评论

发表

最新评论

jghjkj 2 0

略懂

04月28日 10:06

Vic 4 0

嗯! 写的很专业 一脸懵懂的样子

04月26日 10:45

小黑兔 6 0

好高端

04月25日 19:25

leeyun 6 0

手动赞一个

04月25日 17:29

曹瑞 5 0

马克

04月25日 16:10

少女维特 8 0

我就装作看懂的样子

04月25日 16:08

推荐文章

彩龙

Copyright © 2008-2021 彩龙社区 版权所有 All Rights Reserved.

免责声明: 本网不承担任何由内容提供商提供的信息所引起的争议和法律责任。

经营许可证编号:滇B2-20090009-7

下载我家昆明APP 下载彩龙社区APP