内聚、耦合
内聚
内聚的种类(从低到高)
内聚性(Cohesion)衡量模块内部各部分之间的关联程度,高内聚是优秀设计的核心原则。以下是7种内聚类型(按质量从低到高排序),附代码示例说明:
1. 偶然内聚(Coincidental Cohesion)
特点:模块内代码无逻辑关联,仅因巧合被放在一起。
示例:一个工具类包含随机方法:
class Utils {
public static void printDate() { ... } // 打印日期
public static void encryptData() { ... } // 加密数据
public static void connectDB() { ... } // 连接数据库
}
问题:方法之间毫无关系,难以维护。
2. 逻辑内聚(Logical Cohesion)
特点:代码通过参数控制执行不同逻辑,但操作无本质联系。
示例:用一个函数处理多种文件操作:
def file_operation(operation, filename):
if operation == "read":
return read_file(filename)
elif operation == "delete":
return delete_file(filename) # 删除和读取逻辑无关
问题:调用者需知道内部逻辑,新增操作需修改函数。
3. 时间内聚(Temporal Cohesion)
特点:代码因同一时间段执行被放在一起,但无功能关联。
示例:程序初始化时调用的函数:
void startup() {
init_logger(); // 初始化日志
load_config(); // 加载配置
clear_cache(); // 清空缓存
}
问题:虽在启动时调用,但各函数职责分离更合理。
4. 过程内聚(Procedural Cohesion)
特点:代码按特定流程顺序执行,但无数据传递。
示例:用户注册流程:
function registerUser() {
validateInput(); // 验证输入
createUser(); // 创建用户
sendWelcomeEmail(); // 发邮件(依赖前两步成功)
}
改进方向:可拆分为更小单元(如验证服务、邮件服务)。
5. 通信内聚(Communicational Cohesion)
特点:代码操作相同数据,但无严格功能联系。
示例:处理用户数据的函数:
class UserData {
public void updateProfile(User user) { ... } // 更新资料
public void logActivity(User user) { ... } // 记录活动
}
优点:比前几种内聚性更高,但仍可细分(如日志模块独立)。
6. 顺序内聚(Sequential Cohesion)
特点:代码前一步输出是后一步输入,形成流水线。
示例:数据处理流水线:
def process_data(data):
cleaned = clean_data(data) # 清洗数据
transformed = transform(cleaned) # 转换格式
save_to_db(transformed) # 存储结果
优点:逻辑清晰,符合单一职责原则。
7. 功能内聚(Functional Cohesion)★ 理想状态
特点:模块仅完成单一功能,所有代码紧密相关。
示例:计算圆的面积:
class Circle {
private double radius;
public double calculateArea() {
return Math.PI * radius * radius; // 只做一件事
}
}
优点:高复用性、低耦合、易测试维护。
总结对比表
| 内聚类型 | 关键特征 | 质量 | 示例 |
|---|---|---|---|
| 偶然内聚 | 代码随机拼凑 | 最差 | 工具类包含无关方法 |
| 逻辑内聚 | 通过参数分支执行不同逻辑 | 差 | 多合一文件操作函数 |
| 时间内聚 | 同一时间段执行但无功能关联 | 较低 | 程序初始化函数 |
| 过程内聚 | 按流程顺序执行但无数据传递 | 中等 | 用户注册流程 |
| 通信内聚 | 操作相同数据但功能独立 | 良好 | 用户数据更新和日志记录 |
| 顺序内聚 | 前一步输出是后一步输入 | 优秀 | 数据清洗→转换→存储流水线 |
| 功能内聚 | 仅完成单一功能 | 最优 | 计算圆的面积 |
耦合

无数的鸡控制在外公的容器里(无、数、记、控制、外、公、内容)
耦合
耦合是指软件模块之间相互依赖的程度,耦合度越低,系统越容易维护和修改。以下是常见的耦合类型及Java代码示例:
1. 无耦合/无依赖 (No Coupling)
两个模块之间没有任何依赖关系。
// Module A
public class Calculator {
public int add(int a, int b) {
return a + b;
}
}
// Module B
public class Logger {
public void log(String message) {
System.out.println(message);
}
}
2. 数据耦合 (Data Coupling)
模块之间通过参数传递基本数据类型进行通信。
public class OrderProcessor {
public void processOrder(String orderId, double amount) {
// 处理订单逻辑
}
}
public class Main {
public static void main(String[] args) {
OrderProcessor processor = new OrderProcessor();
processor.processOrder("ORD123", 99.99);
}
}
3. 标记耦合 (Stamp Coupling)
模块之间通过传递复合数据结构(如对象)进行通信,但只使用其中部分数据。
public class Customer {
private String name;
private String address;
private String phone;
// getters and setters
}
public class EmailService {
public void sendWelcomeEmail(Customer customer) {
// 只使用customer的name和email
String emailContent = "Dear " + customer.getName() + ", welcome!";
// 发送邮件...
}
}
4. 控制耦合 (Control Coupling)
一个模块通过传递控制信息(如标志)来影响另一个模块的内部逻辑。
public class ReportGenerator {
public void generateReport(boolean isDetailed) {
if (isDetailed) {
generateDetailedReport();
} else {
generateSummaryReport();
}
}
// 其他方法...
}
public class Main {
public static void main(String[] args) {
ReportGenerator generator = new ReportGenerator();
generator.generateReport(true); // 控制生成详细报告
}
}
5. 外部耦合 (External Coupling)
模块依赖于外部系统或工具的接口。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DatabaseAccess {
public Connection getConnection() throws SQLException {
return DriverManager.getConnection(
"jdbc:mysql://localhost:3306/mydb", "user", "password");
}
}
6. 公共耦合 (Common Coupling)
多个模块共享同一个全局数据。
public class GlobalConfig {
public static String DATABASE_URL = "jdbc:mysql://localhost:3306/mydb";
public static int TIMEOUT = 30;
}
public class OrderService {
public void processOrder() {
String url = GlobalConfig.DATABASE_URL;
// 使用全局配置
}
}
public class UserService {
public void getUser() {
String url = GlobalConfig.DATABASE_URL;
// 使用全局配置
}
}
7. 内容耦合 (Content Coupling)
一个模块直接修改或依赖另一个模块的内部数据或实现细节。
public class BankAccount {
public double balance; // 不应该公开字段
// 其他方法...
}
public class AccountManager {
public void manipulateAccount(BankAccount account) {
account.balance += 1000; // 直接修改另一个类的内部字段
}
}
最佳实践
在Java开发中,应该:
- 尽量使用接口耦合而非实现耦合
- 遵循依赖倒置原则(DIP)
- 使用依赖注入(DI)来降低耦合
// 接口耦合示例
public interface MessageService {
void sendMessage(String message);
}
public class EmailService implements MessageService {
@Override
public void sendMessage(String message) {
// 发送邮件实现
}
}
public class NotificationService {
private MessageService messageService;
// 依赖注入
public NotificationService(MessageService messageService) {
this.messageService = messageService;
}
public void notifyUser(String message) {
messageService.sendMessage(message);
}
}
低耦合的设计可以使系统更易于维护、测试和扩展。
浙公网安备 33010602011771号