我是一名学生,最近加入了一家软件开发公司作为实习生。回到大学时,我的一位教授曾经说过,我们必须努力实现“低耦合和高凝聚力”。
我了解低耦合的含义。这意味着将单独组件的代码分开保存,这样一处更改不会破坏另一处的代码。
但是,高凝聚力是什么意思。如果这意味着将同一组件的各个部分很好地集成在一起,我不知道这将如何变得有利。
高凝聚力是什么意思?可以解释一个例子来理解它的好处吗?
我是一名学生,最近加入了一家软件开发公司作为实习生。回到大学时,我的一位教授曾经说过,我们必须努力实现“低耦合和高凝聚力”。
我了解低耦合的含义。这意味着将单独组件的代码分开保存,这样一处更改不会破坏另一处的代码。
但是,高凝聚力是什么意思。如果这意味着将同一组件的各个部分很好地集成在一起,我不知道这将如何变得有利。
高凝聚力是什么意思?可以解释一个例子来理解它的好处吗?
Answers:
从OO角度看凝聚力的一种方法是,如果类中的方法使用任何私有属性。gnat在这里的答案中指出,使用诸如LCOM4(缺乏内聚方法)之类的指标,您可以识别可以重构的类。您想要重构方法或类以使其更具凝聚力的原因是,它使代码设计更易于他人使用。相信我; 解决这些问题时,大多数技术主管和维护程序员都会爱上您。
您可以在构建过程中使用诸如Sonar之类的工具来识别代码库中的低内聚性。我可以想到几个非常常见的情况,即哪些方法的“内聚性”较低:
考虑以下示例:
public class Food {
private int _foodValue = 10;
public void Eat() {
_foodValue -= 1;
}
public void Replenish() {
_foodValue += 1;
}
public void Discharge() {
Console.WriteLine("Nnngghhh!");
}
}
其中一种方法Discharge()
缺乏凝聚力,因为它没有涉及到班上的任何私人成员。在这种情况下,只有一个私人成员:_foodValue
。如果它对类的内部没有任何作用,那么它真的属于那里吗?该方法可以移到另一个可以命名为的类FoodDischarger
。
// Non-cohesive function extracted to another class, which can
// be potentially reused in other contexts
public FoodDischarger {
public void Discharge() {
Console.WriteLine("Nnngghhh!");
}
}
在用Javascript编写代码时,由于函数是一类对象,所以放电可以是自由函数:
function Food() {
this._foodValue = 10;
}
Food.prototype.eat = function() {
this._foodValue -= 1;
};
Food.prototype.replenish = function() {
this._foodValue += 1;
};
// This
Food.prototype.discharge = function() {
console.log('Nnngghhh!');
};
// can easily be refactored to:
var discharge = function() {
console.log('Nnngghhh!');
};
// making it easily reusable without creating a class
这实际上是破坏凝聚力的常见情况。每个人都喜欢实用程序类,但是这些通常都表明设计缺陷,并且大多数时候会使代码库难以维护(因为与实用程序类相关的依赖性很高)。考虑以下类别:
public class Food {
public int FoodValue { get; set; }
}
public static class FoodHelper {
public static void EatFood(Food food) {
food.FoodValue -= 1;
}
public static void ReplenishFood(Food food) {
food.FoodValue += 1;
}
}
在这里,我们可以看到实用程序类需要访问该类中的属性Food
。在这种情况下,实用程序类中的方法根本没有内聚性,因为它需要外部资源来完成其工作。在这种情况下,将方法放在自己正在使用的类中会更好吗(很像第一种情况)?
实用程序类的另一种情况是存在未实现的域对象。编程字符串操作时,程序员的第一个下意识的反应是为其编写实用程序类。就像这里验证两个常见字符串表示的代码一样:
public static class StringUtils {
public static bool ValidateZipCode(string zipcode) {
// validation logic
}
public static bool ValidatePhoneNumber(string phoneNumber) {
// validation logic
}
}
这里最没有意识到的是邮政编码,电话号码或任何其他字符串表示形式都可以是对象本身:
public class ZipCode {
private string _zipCode;
public bool Validates() {
// validation logic for _zipCode
}
}
public class PhoneNumber {
private string _phoneNumber;
public bool Validates() {
// validation logic for _phoneNumber
}
}
@codemonkeyism在本博文中详细介绍了不应直接“处理字符串” 的概念,但与内聚紧密相关,因为程序员通过将逻辑放入实用程序类来使用字符串的方式。
高凝聚力意味着将相似和相关的事物保持在一起,以耦合或融合共享内容,功能,原因或目标的部分。换句话说,低内聚性可能意味着例如功能/类/代码实体,该实体服务于多个目的,而不是“ 指向重点 ”。一种随身携带的思想是做一件事并做好。其他可能包括一个明显的事实,即您在许多地方都没有复制类似的功能。这也提高了代码库的局部性,某些种类的东西在某个地方找到(文件,类,函数集...),而不是分散在周围。
例如,考虑一个有两个或三个目的的类:加载/存储资源(例如文件),然后分析并显示内容。这样的类具有较低的内聚性,因为它管理至少两个根本不相关的单独任务(文件I / O,分析和显示)。高凝聚力的设计可以使用不同的类来加载和存储资源,对其进行分析然后进行显示。
另一方面,低耦合的目的是使不同的事物保持分离-从而使它们之间的交互尽可能少,从而降低了复杂性并简化了设计。
这意味着给定对象的各个部分与该对象的功能密切相关。这意味着就功能或责任而言,对象内几乎没有浪费。反过来,这可以提高对有关对象应用于什么目的的理解。