💡
人们希望将复杂系统分解为低内聚高耦合的模块, 便于并行开发和修改复用
💡
  • 名词解释: 解释耦合与内聚
  • 耦合与内聚
    • 对例⼦**, 说明它们之间的耦合程度与内聚程度, 给出理由
  • 信息隐藏
    • 基本思想
    • 两种常⻅的信息隐藏决策
    • 对例⼦**, 说明其信息隐藏程度好坏

耦合

定义: 在分解之后的模块之间关系的复杂程度.
耦合性从高到低分为不同级别, 耦合性越高则模块的划分越差, 越不利于软件的变更和复用
  1. 内容耦合 → 直接干涉(⼀个模块直接修改另⼀个模块的内容, 如GOTO语句 / 某些语⾔机制⽀持直接更改另⼀个模块的代码 / 改变另⼀个模块的内部数据)
      • 内部类一定是内容耦合
  1. 公共耦合 → 共享数据(全局变量, 模块间共享全局数据, 例⼦: 全局变量, 共享文件, 存储设备)
  1. 重复耦合(模块间有重复代码)
  1. 控制耦合(⼀个模块给另⼀个模块传递控制信息)
  1. 印记耦合(传递数据结构却只是⽤了⼀个部分)
  1. 数据耦合(模块间传参只传需要的数据, 最理想)
123不可接受, 456可接受, 6最理想
💡
以下是内容耦合、公共耦合、重复耦合、控制耦合、印记耦合和数据耦合六种耦合类型的定义与对应示例:

1. 内容耦合(Content Coupling)
定义: 一个模块直接访问或修改另一个模块内部的数据、代码或控制流程.
示例:
说明: 违反封装原则, 模块 A 与 B 的实现细节强绑定, 改动难以维护.

2. 公共耦合(Common Coupling)
定义: 多个模块依赖相同的全局变量.
示例:
说明: 多个模块共享全局状态, 修改会影响所有依赖模块, 增加调试难度.

3. 重复耦合(Duplicate Coupling)
定义: 多个模块中出现重复代码或逻辑, 导致它们对变化的需求产生“逻辑耦合”.
示例:
说明: 同样的税率计算逻辑重复出现, 若税率改变, 需要多处修改, 维护困难.

4. 控制耦合(Control Coupling)
定义: 一个模块通过参数影响另一个模块的控制流程(例如传标志位).
示例:
说明: 调用方控制被调用方执行路径, 违反模块独立性.

5. 印记耦合(Stamp Coupling)
定义: 一个模块传递复杂的数据结构, 只使用其中一部分字段.
示例:
说明: 方法只用到 name, 却传了整个对象, 增加耦合.

6. 数据耦合(Data Coupling)
定义: 模块之间通过参数传递简单、必要的数据进行交互, 是最理想的耦合方式.
示例:
说明: 只传入所需数据, 无多余依赖, 结构清晰、维护方便.

如需配合 UML 图或用更复杂业务场景表示这些耦合类型, 也可继续说明.
💡
耦合的优化方式:
  • 分层风格: 类之间仅进行程序调用与简单数据传递
  • 包设计: 消除重复(减少重复耦合)
  • 分包: 接⼝最小化(减少不必要依赖)
  • 创建者模式: 不增加新的耦合
  • 控制者模式: 解除View与Model的直接耦合(引入Control)

内聚

定义: 一个模块内部联系的紧密程度
内聚性越高越好, 有利于变更和复用.
内聚级别从高到底:
  1. 信息内聚(以数据和功能之间的相互支撑为依据进行模块分解. 模块进⾏许多操作, 每个操作各⾃有各⾃的入口点, 每个操作代码相对独⽴, ⽽且所有操作都在相同的数据结构上进⾏, 形成一个抽象的整体)
      • 常用于实现抽象数据类型, 例如栈模块
  1. 功能内聚(以功能为依据进行模块分解. 模块只执⾏⼀个操作或达到⼀个⽬的)
      • 模块1: 算平方根 模块2: 算最短路径
  1. 通信内聚(模块对相同数据集(与信息内聚区分, 只是取一个集合内的不同部分)执⾏不同的操作)
      • 查书名、查书作者、查书出版商
  1. 过程内聚(模块执行与步骤有关的一些操作, 即模块内各部分是完成一件事的各个步骤)
      • 守门员传球给后卫、后卫传给中场球员、中场球员传给前锋
  1. 时间内聚(与时间有关, 即模块内各部分是在一段时间内先后发生的事件)
      • 起床, 洗脸, 刷牙, 吃早饭
  1. 逻辑内聚(模块组分为一系列操作, 使用哪个由外部决定)
      • 开车去, 坐火车去, 坐飞机去
      • 逻辑相似但没有直接关联
  1. 偶然内聚(多个不相关的操作)
      • 修车、烤⾯包、遛狗、看电影
12最好且出发点不同, 无法相互比较. 一般而言, 函数应该是功能内聚的, 模块应该是信息内聚或功能内聚的, 面向对象方法中的类应该是信息内聚和功能内聚兼顾的.
345出发点不同无法比较, 可以接受且无法避免. 需要限定这三种内聚的使用, 让负责控制过程的少量模块(控制器对象)是通信/时间/过程内聚的, 让多数执行具体功能的模块是功能内聚或信息内聚的.
67不可接受, 一定要进行优化.
💡
内聚的优化方式:
  • 分层: 层间职责分配/层内分包均⾼内聚
  • 信息专家模式(功能与其数据内聚在同一个类)
  • 控制器与委托式控制风格

信息隐藏

核心设计思路:
  • 每个模块都隐藏⼀个重要的设计决策(即职责的具体实现细节)
  • 每个模块都承担一定的职责, 对外体现为⼀份契约, 并且在这份契约之下隐藏着只有这个模块知道的决策或者说秘密. 决策实现的细节(特别是容易改变的细节)只有模块自己知道
  • 抽象出来的就是接口, 隐藏起来的就是实现.
所谓要隐藏的信息, 即模块的秘密, 其实就是指对模块来说容易变化的地方, 主要分为两类:
  1. 根据需求而分配的职责(因为需求容易变化);
  1. 模块内部的实现机制(实现细节容易改动).
隐藏的目的就是希望把未来的改变限制在本地, 隐藏独立变化的系统细节, 分隔不一致变化的模块, 只暴露出不易变化的接口.
所以, 信息隐藏实际上就是隐藏你认为会改变的设计决策, 把它们秘密指派给单独的模块进行封装, 使得就算该决策发生变化也不会对其他部分产生影响.
💡
信息隐藏的优化方式:
  • 分层与分包: 消除职责重复、最小化接⼝
    • View能否独立?
    • 数据库连接能否独立?
  • 模块信息隐藏: 模块需求分配与接⼝定义
  • 类信息隐藏: 协作设计, 接⼝定义
  • 变化设计? 分层风格、RMI
Loading...