【内聚】
1.内聚的定义
一个模块内部元素彼此结合的紧密程度。其中关键字:模块、元素、结合
模块:大到子系统,小到一个函数,都可以看成一个模块
元素:
模块:包、命名空间等
包:类、接口、全局数据等
类/接口:方法、属性
函数:内部的代码
结合: 用“凝聚力”来理解,更贴切。
假如说一个类的方法,都依赖于类自身的其他方法,我们说它内聚高。如果一个类的方法依赖外部类的方法,那么这个类的内聚性一定不高吗?不一定。判断一个模块内部元素的内聚性是否高,要看这个模块内部元素的凝聚力。什么是凝聚力?凝聚力就是对模块本身职责的专注程度。
例如:操作数据库的CURD类。CURD方法之间没有任何结合的关系。但这四个方法是高内聚的。因为它们都专注于CURD类本身的职责。
2.内聚的分类
偶然内聚:是内聚性最差的一种。仅仅是因为某个和本身业务无关的原因而划分到同一个模块中。例如最常见的,Utils包。这个包主要是提供一些常用的小工具,像个百宝箱一样。这种包中的各个功能模块、各个类专注的职责都是独立的,仅是为了方便取用而划分到了一起。
逻辑内聚:模块内的元素属于同一个比较宽泛的类别,但元素的职责上可能不一样。例如:鼠标、键盘、显示器、打印机,都同属于IO设备,但这样的内聚相对还是比较弱的。鼠标、键盘归类为输入设备模块,显示器、打印机归类为输出设备模块。这样,内聚性会更高一点。
时间内聚:这种内聚一般在函数中比较常见。模块内的元素之所以被划分到一个模块内,是因为这些元素的动作在时间上很相近。或者说在某一事件发生、某一状态改变时会调用这些元素进行业务处理。例如:异常处理。抛出异常后,一般我们要做释放资源、记录日志、通知用户这些动作都要执行。
过程内聚:这种内聚一般在函数中比较常见。这类元素一般是在处理某个业务操作时,必须按照一定的顺序来执行。例如:读/写文件操作。1.判断文件是否存在,2文件是否有权限,3打开文件,4读/写文件。以上这4步的函数都是为了完成读/写文件这一个操作,并且顺序不能错乱。那么把这4个函数封装在一个函数中,那么它们之间就是过程内聚。
信息内聚:元素被划分到一个模块中是因为这些元素所操作的数据都是相同的数据 或 数据类型 或 数据源。例如学生信息类中有对学生信息操作的CURD方法,那么这些方法在这个类中的内聚就是信息内聚。
顺序内聚:一个元素执行后的输出,是一个元素执行前的输入,元素之间这种环环相扣的关系就是顺序内聚。例如:规则引擎,一个函数负责读取配置,根据读取的配置输出转换后的执行指令,另一个函数读取指令进而去执行。
功能内聚:功能内聚是最好的一种内聚方式。模块内部的元素之所以被划分到一个模块中,是因为都是为了完成同一个单一任务。同一个单一任务这个概念比较难界定。因为前面说的IO设备、异常处理、读写文件也都是单一任务。功能内聚中的单一任务是指,元素的功能只为了完成所在模块的任务,别无其他用途。例如:判断文件是否存在这个函数,既可以在读写文件中用,也可以在删除文件中用;再例如,发薪水模块中的计算个人所得税函数,这个函数就是功能内聚的,因为它除了用在发薪水中,其他业务中用不上。