CPP-Summit-2020 学习:多范式融合的Modern C++ 软件设计(上)

一、什么是“编程范式”(Programming Paradigm)

编程范式是程序员“如何看待程序”的一种基本思维方式。

  • 它不是语法特性
  • 不是某种具体语言
  • 而是一种设计程序的世界观
    这一概念最早由
    Robert Floyd
    在1979年图灵奖演讲中系统提出。

编程范式决定了我们:

  • 程序由什么构成?
  • 如何组织代码?
  • 如何理解问题域(Domain)?
  • 如何做抽象?

二、从 Turing Machine 到现代 C++:范式演进

可以把演进过程理解为:

从“机器如何执行”(How)
到“我要表达什么”(What)
再到“为什么这样设计”(Why)

三、机器/汇编语言(1950+)

思维方式:控制机器

程序 = 指令序列
开发者关注:

  • 寄存器
  • 内存地址
  • 跳转
  • CPU状态
    本质模型:
    图灵机(Turing Machine)
    理论上:
    程序 = 状态转移函数 程序 = 状态转移函数 程序=状态转移函数
    δ ( q , s ) → ( q ′ , s ′ , d ) \delta(q, s) \rightarrow (q', s', d) δ(q,s)(q,s,d)
    表示:
  • 当前状态 q q q
  • 当前符号 s s s
  • 转移到 q ′ q' q
  • 写入 s ′ s' s
  • 向左或右移动 d d d

示例(类汇编风格 C++)

#include <iostream>
// 模拟“机器式”思维:手动控制状态
int main() {
    int acc = 0;        // 累加器
    int i = 0;          // 模拟寄存器
    // 模拟跳转 + 状态控制
    while (true) {
        if (i >= 10)
            break;      // 类似跳转指令
        acc += i;       // 手动修改状态
        i++;
    }
    std::cout << acc << std::endl;
}

特点:

  • 关注状态
  • 关注执行顺序
  • 强依赖“如何做”(How)

四、过程化编程(1950+)

代表语言:C

思维方式:程序 = 函数集合

  • 数据 + 操作分离
  • 关注步骤
  • Top-Down 设计
    程序本质:
    程序 = 一组函数 f 1 , f 2 , . . . , f n 程序 = 一组函数 f_1, f_2, ..., f_n 程序=一组函数f1,f2,...,fn

示例

#include <iostream>
// 过程:求和
int sum(int n) {
    int result = 0;             // 局部状态
    for (int i = 0; i <= n; ++i) {
        result += i;            // 逐步计算
    }
    return result;
}
int main() {
    std::cout << sum(10) << std::endl;
}

特点:

  • 关注“怎么做”
  • 强调步骤
  • 可读性提升

五、面向对象编程(196X)

代表人物:
Alan Kay

思维方式:程序 = 对象的协作

核心思想:

  • 封装(Encapsulation)
  • 继承(Inheritance)
  • 多态(Polymorphism)
    程序建模方式:
    系统 = 对象集合 + 对象之间的消息传递 系统 = 对象集合 + 对象之间的消息传递 系统=对象集合+对象之间的消息传递
    从:

“怎么做”
变成:
“谁来做”

示例(C++ OOP)

#include <iostream>
// 抽象:数字计算器
class Calculator {
private:
    int value;  // 封装状态
public:
    Calculator(int v) : value(v) {}
    void add(int x) {
        value += x;  // 操作封装在对象内部
    }
    int get() const {
        return value;
    }
};
int main() {
    Calculator calc(0);
    calc.add(10);
    std::cout << calc.get() << std::endl;
}

范式变化:

  • 从“步骤”变成“角色”
  • 更贴近现实世界建模
  • 强调 Domain

六、多范式融合(198X)

C++ 的核心思想:

不是选择一种范式
而是融合多种范式
代表人物:
Bjarne Stroustrup
C++支持:

  • 过程式
  • 面向对象
  • 泛型
  • 函数式
  • 元编程

七、函数式编程(2010+ 再次兴起)

函数式编程强调:

  • 不可变数据(Immutable)
  • 无副作用(Pure Function)
  • 数学函数式思维
    数学定义:
    f ( x ) = y f(x) = y f(x)=y
    没有状态变化。

示例(函数式风格 C++)

#include <iostream>
#include <numeric>
#include <vector>
int main() {
    std::vector<int> data{1,2,3,4,5};
    // 累加:函数式表达
    int result = std::accumulate(
        data.begin(),
        data.end(),
        0,
        [](int acc, int x) {
            return acc + x;  // 无副作用
        }
    );
    std::cout << result << std::endl;
}

特点:

  • 强调表达式
  • 强调“是什么”
  • 更接近数学

八、What / How / Why 的演进


阶段关注点思维层级
汇编How(怎么做)机器
过程How算法步骤
面向对象Who 做领域建模
函数式What 是数学映射
现代C++Why架构 + 抽象设计

九、编程范式与软件建模的关系

编程范式影响:

  • 代码组织方式
  • 抽象层次
  • 架构风格
  • 可维护性
  • 可扩展性
    例如:
  • OOP → DDD
  • 函数式 → 数据流架构
  • 泛型 → 高性能库设计

十、现代 C++ 的真正本质

现代 C++(C++20以后):

是一个多范式、零成本抽象语言
抽象成本理论:
抽象成本 ≈ 0 抽象成本 \approx 0 抽象成本0
(理想目标)
即:

  • 高层抽象
  • 机器级性能
    这也是 C++ 在系统领域长期存在的原因。

十一、总结:范式演进本质

范式演进不是语法升级,而是:

抽象能力的升级
从:

  • 控制机器
    到:
  • 控制流程
    到:
  • 控制对象
    到:
  • 控制抽象
    到:
  • 控制领域模型
    最终:

控制“复杂性”

C++语言编程范式演进(深度解析版)

C++的发展不是“版本升级史”,而是:

抽象能力递进史 + 多范式融合史
可以用一个抽象公式表示:
C + + = 性能 + 抽象 + 多范式融合 C++ = 性能 + 抽象 + 多范式融合 C++=性能+抽象+多范式融合
或者更形式化一点:
L a n g u a g e   P o w e r = A b s t r a c t i o n   L e v e l × Z e r o   C o s t   G u a r a n t e e Language\ Power = Abstraction\ Level \times Zero\ Cost\ Guarantee Language Power=Abstraction Level×Zero Cost Guarantee

一、历史阶段与范式跃迁

① 1972:C

核心范式:过程式编程
特点:

  • 手动内存管理
  • 指针操作
  • 函数驱动
  • 面向机器
    程序模型:
    P r o g r a m = F u n c t i o n s + D a t a Program = { Functions } + { Data } Program=Functions+Data
    关注:

How(怎么做)

② 1979:C with Classes

发明人:
Bjarne Stroustrup
引入:

  • class
  • 构造/析构
  • 封装
    开始支持:

面向对象范式(OOP)
程序模型转变为:
S y s t e m = O b j e c t s + M e s s a g e P a s s i n g System = Objects + Message Passing System=Objects+MessagePassing

③ 1990:模板 + 异常

这是第一次重大范式跃迁。
新增:

  • Templates(泛型编程)
  • Exception(错误控制流分离)

模板的数学意义

模板本质是“类型函数”:
F : T y p e → C o d e F : Type \rightarrow Code F:TypeCode
例如:

#include <iostream>
// 泛型函数模板
template<typename T>
T add(T a, T b) {
    return a + b;   // 与类型无关的抽象
}
int main() {
    std::cout << add(1, 2) << std::endl;       // int
    std::cout << add(1.5, 2.5) << std::endl;   // double
}

特点:

  • 算法与类型解耦
  • 编译期多态

④ 1994:STL —— 泛型编程革命

核心人物:
Alexander Stepanov
STL带来:

  • Iterator抽象
  • 算法与容器分离
  • Traits技术
  • 模板元编程
    核心思想:
    A l g o r i t h m ( I t e r a t o r ) Algorithm(Iterator) Algorithm(Iterator)
    而不是:
    A l g o r i t h m ( C o n t a i n e r ) Algorithm(Container) Algorithm(Container)
    示例:
#include <vector>
#include <algorithm>
#include <iostream>
int main() {
    std::vector<int> v{1,2,3};
    // 泛型算法与容器解耦
    std::for_each(v.begin(), v.end(),
        [](int x) {
            std::cout << x << std::endl;
        });
}

这一阶段标志着:

C++成为真正的“泛型编程语言”

⑤ 1998–2003:标准化阶段

  • C++98
  • C++03
    目标:
  • 语言稳定
  • 模板完善
  • STL成熟
    形成真正的:

多范式基础框架

二、现代C++阶段(2011之后)

2011是第二次重大跃迁。

⑥ C++11

新增能力:

  • Lambda
  • 右值引用
  • 移动语义
  • auto
  • 可变参数模板
  • constexpr
  • 标准线程库

1⃣ 右值引用与移动语义

传统复制成本:
C o s t ( c o p y ) = O ( n ) Cost(copy) = O(n) Cost(copy)=O(n)
移动语义:
C o s t ( m o v e ) ≈ O ( 1 ) Cost(move) \approx O(1) Cost(move)O(1)
示例:

#include <vector>
// 返回局部对象
std::vector<int> create() {
    std::vector<int> v{1,2,3};
    return v;   // 移动而不是拷贝
}
int main() {
    auto data = create();  // 利用move语义
}

意义:

高抽象 + 零额外成本

2⃣ Lambda —— 函数式能力增强

#include <iostream>
int main() {
    auto add = [](int a, int b) {
        return a + b;   // 无副作用表达式
    };
    std::cout << add(3,4) << std::endl;
}

程序逐渐表达为:
f ( x ) = y f(x) = y f(x)=y

⑦ C++14

增强:

  • 返回值自动推导
  • 泛型Lambda
  • 放宽constexpr
  • 变量模板
    示例(泛型Lambda):
auto add = [](auto a, auto b) {
    return a + b;  // 自动类型推导
};

泛型进一步“函数化”。

⑧ C++17

新增:

  • 构造函数推导
  • 折叠表达式
  • constexpr if
  • std::variant
  • 并发内存模型增强

constexpr if 示例

#include <iostream>
#include <type_traits>
template<typename T>
void print(T value) {
    if constexpr(std::is_integral_v<T>) {
        std::cout << "int: " << value << std::endl;
    } else {
        std::cout << "other: " << value << std::endl;
    }
}

这是:

编译期分支

⑨ C++20

重大升级:

  • Concepts
  • Ranges
  • Coroutines
  • Modules

Concepts —— 类型系统跃迁

旧模板:
T ∈ A n y T y p e T \in AnyType TAnyType
新模板:
T ∈ C o n c e p t T \in Concept TConcept
示例:

#include <concepts>
template<typename T>
concept Addable = requires(T a, T b) {
    a + b;
};
template<Addable T>
T add(T a, T b) {
    return a + b;
}

泛型进入:

类型约束时代

协程(Coroutines)

支持:

  • 异步编程
  • 生成器模式
  • 状态机自动化
    程序抽象为:
    S t a t e M a c h i n e ⇒ C o r o u t i n e StateMachine \Rightarrow Coroutine StateMachineCoroutine

三、C++范式演进的四大特点

① 逐步加入新的设计范式

阶段新范式
1970s过程式
1980s面向对象
1990s泛型
2000s模板元编程
2011函数式 + 并发
2020类型系统化

② 持续优化完备性

例如:

  • RAII
  • 智能指针
  • move语义
  • constexpr
  • Concepts
    目标:
    抽象成本 → 0 抽象成本 \rightarrow 0 抽象成本0

③ 强调融合

C++不是“纯函数式”
也不是“纯OOP”
而是:
M u l t i   P a r a d i g m = O O P + G e n e r i c + F u n c t i o n a l + M e t a + S y s t e m Multi\ Paradigm = OOP + Generic + Functional + Meta + System Multi Paradigm=OOP+Generic+Functional+Meta+System

④ 社区驱动演进

  • 工业实践
  • 标准委员会
  • Boost生态
  • 开源贡献
    范式的成熟来自:

实践 → 总结 → 标准化

四、本质总结

C++的演进可以理解为:
控制机器 → 控制流程 → 控制对象 → 控制类型 → 控制抽象 控制机器 → 控制流程 → 控制对象 → 控制类型 → 控制抽象 控制机器控制流程控制对象控制类型控制抽象
它最终解决的问题不是“写代码”,而是:

如何在保证性能的前提下控制复杂性

02 · C++编程范式剖析 —— 过程式设计(Procedural Design)

一、过程式设计的核心思想

著名计算机科学家
Niklaus Wirth
提出过一句非常经典的话:

程序 = 数据结构 + 算法
Program = Data Structures + Algorithms
可以形式化表示为:
P r o g r a m = D a t a + A l g o r i t h m Program = Data + Algorithm Program=Data+Algorithm
其中:

  • Data:数据结构(struct、数组、内存布局)
  • Algorithm:对数据的操作步骤(函数、流程)

二、从图灵机模型理解过程式设计

过程式编程非常贴近图灵机模型:
S t a t e n e x t = f ( S t a t e c u r r e n t , I n p u t ) State_{next} = f(State_{current}, Input) Statenext=f(Statecurrent,Input)
程序执行本质:

  • 修改状态
  • 顺序执行
  • 显式控制流程
    关注重点:

How —— “怎么做”

三、图示结构解析(你给的图)

过程 数据 Procedure

图中表达的是:
左侧:
多个 Procedure(过程/函数)
右侧:
一个共享的数据区域
箭头表示:

  • 过程可以读写数据
  • 数据对多个过程开放
    结构本质:
Procedure A → 数据
Procedure B → 数据
Procedure C → 数据

数据是中心,函数围绕数据操作。

四、C++中的过程式设计示例

示例1:典型过程式风格

#include <iostream>
// 全局数据(共享数据)
int balance = 0;  // 所有函数都可以访问
// 算法1:存钱
void deposit(int amount) {
    balance += amount;  // 修改全局状态
}
// 算法2:取钱
void withdraw(int amount) {
    balance -= amount;  // 修改同一份数据
}
// 算法3:查询余额
void print_balance() {
    std::cout << balance << std::endl;
}
int main() {
    deposit(100);
    withdraw(30);
    print_balance();  // 输出70
}

特点:

  • 数据与函数分离
  • 数据全局共享
  • 函数之间通过共享数据“间接通信”

五、过程式设计的优点

① 贴近机器模型

它几乎等价于:
M e m o r y + I n s t r u c t i o n s Memory + Instructions Memory+Instructions
优点:

  • 性能可控
  • 内存可控
  • 易于做底层优化
  • 适合系统编程
    这也是:
  • 操作系统内核
  • 嵌入式系统
  • 驱动程序
    大量使用C语言的原因。

② 可预测性强

执行路径清晰:

main → f1 → f2 → f3

流程可视化清楚。

六、过程式设计的缺点(核心问题)

① 全局数据导致高耦合

如果多个函数操作同一数据:

f1()
f2()
f3()

都依赖:

global_data

那么耦合度可以理解为:
C o u p l i n g ∝ N f u n c t i o n s × S h a r e d D a t a Coupling \propto N_{functions} \times SharedData CouplingNfunctions×SharedData
函数越多,共享数据越复杂,系统复杂度指数增长。

举例:问题演示

int counter = 0;
void increment() {
    counter++;
}
void reset() {
    counter = 0;
}
void print() {
    std::cout << counter << std::endl;
}

问题:

  • 任意函数都可以修改counter
  • 很难追踪状态变化来源
  • 容易出现隐藏Bug

② 可复用性差

函数往往依赖外部状态。
如果想复用increment:
必须保证:

存在一个全局counter

这降低了模块独立性。

③ 响应变化能力弱

如果数据结构变化:

int balance;

改为:

struct Account {
    int balance;
    int id;
};

所有相关函数都必须修改。

七、过程式 vs 面向对象(对比理解)


特征过程式面向对象
数据共享封装
组织方式函数集合对象集合
依赖关系高耦合低耦合
扩展能力较弱较强
贴近机器非常贴近稍抽象

八、什么时候应该使用过程式设计?

过程式并没有“过时”。
适合场景:

  • 算法密集型代码
  • 数值计算
  • 内核模块
  • 性能极端敏感场景
  • 小型工具程序
    例如:
    排序算法:
void quick_sort(int arr[], int left, int right) {
    if (left >= right)
        return;
    int i = left;
    int j = right;
    int pivot = arr[left];
    while (i < j) {
        while (i < j && arr[j] >= pivot)
            j--;
        while (i < j && arr[i] <= pivot)
            i++;
        std::swap(arr[i], arr[j]);
    }
    std::swap(arr[left], arr[i]);
    quick_sort(arr, left, i - 1);
    quick_sort(arr, i + 1, right);
}
quick_sort 流程图 quick_sort(arr[], left, right) quick_sort(arr, left, right) left >= right ? base case 终止条件 YES return NO 初始化 i = left, j = right pivot = arr[left] i < j ? 外层 while 循环 NO YES i<j && arr[j]>=pivot ? 从右找小于 pivot 的元素 YES j-- NO i<j && arr[i]<=pivot ? 从左找大于 pivot 的元素 YES i++ NO swap(arr[i], arr[j]) 交换找到的逆序对 回到外层 while swap(arr[left], arr[i]) pivot 归位到正确位置 i arr[i] == pivot 已就位 左侧 arr[left..i-1] <= pivot,右侧 arr[i+1..right] >= pivot 递归左子数组 quick_sort(arr, left, i-1) 递归右子数组 quick_sort(arr, i+1, right) 函数返回 图例: 开始/结束 条件判断 处理操作 交换操作 递归调用 详细步骤演示 输入数组:[5, 3, 8, 1, 4] quick_sort(arr, 0, 4) pivot = arr[left] = arr[0] = 5 i=0, j=4 Step 0 — 初始状态 pivot = 5 (arr[0]), i = 0, j = 4 [0] [1] [2] [3] [4] 5 3 8 1 4 ↑ i=0 ↑ j=4 pivot j← 向左扫描找 < pivot(5) 的元素 i→ 向右扫描找 > pivot(5) 的元素 Step 1 — 内层 while①:j 从右向左扫描 检查 arr[j]=arr[4]=4 < pivot(5) → 停止,j=4 [0] [1] [2] [3] [4] 5 3 8 1 4 ↑ i=0 ↑ j=4 停! arr[4]=4 < pivot=5 ✓ j 停在 4 继续内层 while②: i→ Step 2 — 内层 while②:i 从左向右扫描 检查 arr[i]=arr[0]=5 <= pivot(5) → i++;arr[1]=3 <= 5 → i++;arr[2]=8 > 5 → 停止,i=2 [0] [1] [2] [3] [4] 5 3 8 1 4 ↑ i=2 停! ↑ j=4 arr[2]=8 > pivot=5 ✓ i 停在 2 i=2 < j=4 → 执行 swap(arr[2], arr[4]) Step 3 — swap(arr[2], arr[4]) 交换 8 和 4 i=2 < j=4,交换 arr[i]=8 与 arr[j]=4 交换前: 5 3 8 1 4 ⇄ 交换 交换后: 5 3 4 1 8 ↑ i=2 ↑ j=4 Step 4 — 第二轮外层 while (i=2 < j=4) while①: arr[4]=8 >= pivot(5) → j--; arr[3]=1 < pivot(5) → j停在3 while②: arr[2]=4 <= pivot(5) → i++; arr[3]=1 <= pivot(5) → i++; i=j=3 → i<j不满足,停 [0] [1] [2] [3] [4] 5 3 4 1 8 ↑ i=j=3 i≥j,退出 while i=j=3,外层 while 退出 执行 swap(arr[left], arr[i]) = swap(arr[0], arr[3]) Step 5 — swap(arr[left], arr[i]) = swap(arr[0], arr[3]) pivot 归位! 交换 arr[0]=5 与 arr[3]=1,pivot=5 落到索引 3 的位置 交换前: 5 3 4 1 8 ⇄ pivot 归位 交换后: 1 3 4 5 8 ✓ pivot=5 就位 左子 [1,3,4] 右子 [8] Step 6 — 递归分治树(完整展开) quick_sort([5,3,8,1,4], 0, 4) pivot=5 → [1,3,4] | 5 | [8] left right quick_sort([1,3,4], 0, 2) pivot=1 → [] | 1 | [3,4] quick_sort([8], 3, 3) left=right=3 → return ✓ left>right → return ✓ (空子数组) quick_sort([3,4], 1, 2) pivot=3 → [] | 3 | [4] return ✓ (单元素3) return ✓ (单元素4) ✓ 排序完成!最终结果 [5, 3, 8, 1, 4] → 排序后 → [1, 3, 4, 5, 8] 1 3 4 5 8 原 pivot 时间复杂度分析 情形 时间复杂度 空间复杂度 触发条件 最优 / 平均 O(n log n) O(log n) pivot 每次接近中位数 最差 O(n²) O(n) 已排序/全相同数组 此实现 pivot 取 arr[left],对已排序数组退化为 O(n²);可改用随机 pivot 或三数取中优化 quick_sort 演示 · arr=[5,3,8,1,4] · C++ CPP-Summit

这里用OOP反而会增加复杂度。

#include <iostream>
#include <vector>
#include <algorithm>    // 用于 std::sort 做对比验证
#include <random>       // 用于生成随机数
#include <ctime>        // 用于设置随机种子
// 你提供的快速排序实现(原版)
void quick_sort(int arr[], int left, int right) {
    if (left >= right)
        return;
    int i = left;
    int j = right;
    int pivot = arr[left];
    while (i < j) {
        while (i < j && arr[j] >= pivot)
            j--;
        while (i < j && arr[i] <= pivot)
            i++;
        std::swap(arr[i], arr[j]);
    }
    std::swap(arr[left], arr[i]);
    quick_sort(arr, left, i - 1);
    quick_sort(arr, i + 1, right);
}
// 打印数组的辅助函数
void print_array(const int arr[], int n, const std::string& title = "") {
    if (!title.empty()) {
        std::cout << title << ": ";
    }
    for (int i = 0; i < n; ++i) {
        std::cout << arr[i];
        if (i < n - 1) std::cout << ", ";
    }
    std::cout << "\n";
}
// 检查数组是否已排序(升序)
bool is_sorted(const int arr[], int n) {
    for (int i = 1; i < n; ++i) {
        if (arr[i - 1] > arr[i]) {
            return false;
        }
    }
    return true;
}
int main() {
    std::srand(static_cast<unsigned>(std::time(nullptr)));
    // 测试用例列表
    std::vector<std::vector<int>> test_cases = {
        {},                             // 空数组
        {5},                            // 只有一个元素
        {3, 1},                         // 两个元素
        {1, 2, 3, 4, 5},               // 已经有序
        {5, 4, 3, 2, 1},               // 逆序
        {4, 2, 4, 2, 4, 2},            // 有大量重复元素
        {7, 7, 7, 7, 7},               // 全相同
        {10, 80, 30, 90, 40, 50, 70},  // 经典例子
        {64, 34, 25, 12, 22, 11, 90}   // 另一个常见例子
    };
    // 生成一个较大的随机数组
    std::vector<int> large_random(100);
    std::generate(large_random.begin(), large_random.end(), []() {
        return std::rand() % 1000;
    });
    test_cases.push_back(large_random);
    int case_num = 1;
    for (const auto& vec : test_cases) {
        int n = vec.size();
        std::cout << "\n=== 测试用例 " << case_num++ << " (大小: " << n << ") ===\n";
        if (n == 0) {
            std::cout << "空数组 → 已排序\n";
            continue;
        }
        // 原始数组
        std::cout << "原始: ";
        for (size_t i = 0; i < vec.size(); ++i) {
            std::cout << vec[i] << (i < vec.size() - 1 ? ", " : "\n");
        }
        // 复制一份给 quick_sort 使用(因为会修改原数组)
        std::vector<int> arr = vec;
        quick_sort(arr.data(), 0, n - 1);
        // 打印排序结果
        std::cout << "排序后: ";
        for (int x : arr) {
            std::cout << x << " ";
        }
        std::cout << "\n";
        // 验证是否正确排序
        if (is_sorted(arr.data(), n)) {
            std::cout << "[正确] 数组已升序排序 ✓\n";
        } else {
            std::cout << "[错误] 排序失败!\n";
        }
        // 额外验证:与 std::sort 结果对比
        std::vector<int> std_sorted = vec;
        std::sort(std_sorted.begin(), std_sorted.end());
        bool match = (arr == std_sorted);
        std::cout << (match ? "[通过] 与 std::sort 结果一致 ✓" : "[失败] 与 std::sort 不一致 ✗") << "\n";
    }
    std::cout << "\n所有测试用例执行完毕。\n";
    return 0;
}

https://godbolt.org/z/sT5eehds5

九、从复杂度角度理解过程式的局限

假设:

  • n n n 个函数
  • m m m 个共享数据
    那么潜在依赖关系规模为:
    O ( n × m ) O(n \times m) O(n×m)
    如果全部函数访问全部数据:
    O ( n m ) O(nm) O(nm)
    当系统变大时,复杂度爆炸。

十、过程式的历史意义

过程式是:

第一代“结构化编程思想”
解决了:

  • goto滥用问题
  • 流程混乱问题
  • 无结构代码问题
    它是后续范式的基础。

十一、本质总结

过程式设计的哲学是:

数据是核心
函数是操作
程序运行本质:
S t a t e → M o d i f i e d   S t a t e State \rightarrow Modified\ State StateModified State
优点:

  • 高性能
  • 可控
  • 简洁
    缺点:
  • 高耦合
  • 扩展困难
  • 复杂系统难维护

软件设计对“确定性”的追求(C++视角深度解析)

在系统级软件(操作系统、数据库、嵌入式、交易系统)中,确定性(Determinism) 是核心目标之一。
可以抽象成一句话:
S a m e   I n p u t ⇒ S a m e   B e h a v i o r Same\ Input \Rightarrow Same\ Behavior Same InputSame Behavior
进一步形式化:
P r o g r a m ( I n p u t , E n v i r o n m e n t ) = O u t p u t + R e s o u r c e U s a g e Program(Input, Environment) = Output + ResourceUsage Program(Input,Environment)=Output+ResourceUsage
如果在相同输入与环境下:

  • 输出一致
  • 内存使用一致
  • 指令路径一致
  • 二进制结构一致
    那么系统就是“确定性的”。

一、确定性的两个维度


类型关注点
静态确定性编译期结构可控
动态确定性运行期行为可控

二、静态确定性(Static Determinism)

静态确定性关注:

编译完成后的二进制是否可预测、可控制

1⃣ 代码符号与 ABI 的确定性控制

(1)Name Mangling 可追溯

C++支持函数重载,编译器会对符号“改名”(Name Mangling)。
例如:

int add(int a, int b);
double add(double a, double b);

底层会生成不同符号名。
如果想控制ABI稳定性,可以使用:

extern "C" int add(int a, int b);

这样:

  • 禁止name mangling
  • 保证符号稳定
  • 便于跨语言调用

(2)Inline 的可控性

inline可能导致:

  • 代码膨胀
  • ABI变化
  • 调试困难
    可以通过:
  • 不在头文件中实现
  • 使用编译选项控制
  • 避免过度模板
    保证:
    B i n a r y   S i z e = P r e d i c t a b l e Binary\ Size = Predictable Binary Size=Predictable

2⃣ 二进制大小的确定性控制

(1)模板显式实例化

模板默认是“按需实例化”:

template<typename T>
T square(T x) {
    return x * x;
}

如果在多个文件使用不同类型:
会生成多个版本。
可以显式具现:

// 显式实例化
template int square<int>(int);

这样:

  • 控制生成数量
  • 避免隐式爆炸

(2)禁用 RTTI

RTTI(运行时类型识别)会:

  • 增加typeinfo
  • 增加vtable开销
  • 增加异常依赖
    编译选项:
-fno-rtti

可使:
B i n a r y   S i z e ↓ Binary\ Size \downarrow Binary Size

(3)禁用异常

异常机制需要:

  • 栈展开表
  • 额外运行时支持
    可使用:
-fno-exceptions

效果:

  • 减少二进制
  • 提升路径确定性
  • 避免隐藏跳转

三、动态确定性(Runtime Determinism)

动态确定性关注:

程序运行时资源与行为是否可预测

四、内存使用的确定性控制

1⃣ placement new

允许在指定地址构造对象。

#include <new>
#include <iostream>
int main() {
    alignas(int) char buffer[sizeof(int)];  
    // buffer对齐到int大小
    int* p = new (buffer) int(42);  
    // 在buffer中构造int
    std::cout << *p << std::endl;
    // p->~int();  // 手动调用析构函数
}

https://godbolt.org/z/TzjYjrGnP
优点:

  • 无堆分配
  • 无malloc
  • 内存来源完全可控

2⃣ alignof

获取类型对齐要求:

#include <iostream>
struct A {
    double d;
    int i;
};
int main() {
    std::cout << alignof(A) << std::endl;
}

保证:
A d d r e s s   m o d   A l i g n m e n t = 0 Address \bmod Alignment = 0 AddressmodAlignment=0

3⃣ std::align

手动调整指针满足对齐:

#include <memory>
#include <iostream>
int main() {
    char buffer[64];
    void* ptr = buffer;
    std::size_t space = sizeof(buffer);
    std::align(alignof(double), sizeof(double), ptr, space);
    // ptr现在满足double对齐
}

4⃣ std::pmr::memory_resource

C++17引入多态内存资源。
可以控制:

  • 内存池
  • 栈内分配
  • 固定大小分配
    示例:
#include <memory_resource>
#include <vector>
int main() {
    std::byte buffer[1024];
    std::pmr::monotonic_buffer_resource pool(buffer, sizeof(buffer));
    std::pmr::vector<int> vec(&pool);  
    // 使用指定内存资源
    vec.push_back(1);
}

优点:

  • 不走全局new
  • 不走malloc
  • 内存分配路径固定

五、运行时指令路径的确定性控制

1⃣ 禁用 RTTI / 异常

避免:

  • 动态类型判断
  • 栈展开
  • 不可预测跳转
    使程序更接近:
    L i n e a r   C o n t r o l   F l o w Linear\ Control\ Flow Linear Control Flow

2⃣ 多线程内存模型

C++11引入正式内存模型。
核心问题:
R e o r d e r i n g Reordering Reordering
CPU可能重排序。
C++提供:

  • memory_order_relaxed
  • memory_order_acquire
  • memory_order_release
  • memory_order_seq_cst
    最强一致性:
    S e q u e n t i a l   C o n s i s t e n c y Sequential\ Consistency Sequential Consistency
    示例:
#include <atomic>
std::atomic<int> flag{0};
void writer() {
    flag.store(1, std::memory_order_release);
}
void reader() {
    if (flag.load(std::memory_order_acquire)) {
        // 保证看到完整写入
    }
}

保证:
W r i t e → R e a d   o r d e r i n g Write \rightarrow Read\ ordering WriteRead ordering

六、为什么系统软件极度追求确定性?

在以下场景:

  • 实时系统
  • 金融交易
  • 内核
  • 嵌入式
  • 游戏引擎
    需要:
  • 可预测延迟
  • 无隐藏开销
  • 无异常路径
  • 内存稳定
    否则:
    L a t e n c y   J i t t e r ↑ Latency\ Jitter \uparrow Latency Jitter

七、静态 + 动态确定性的统一

可以抽象为:
D e t e r m i n i s m = C o m p i l e T i m e C o n t r o l + R u n t i m e C o n t r o l Determinism = CompileTimeControl + RuntimeControl Determinism=CompileTimeControl+RuntimeControl
C++之所以长期存在于系统领域,
正是因为它允许你:

  • 控制ABI
  • 控制符号
  • 控制二进制
  • 控制内存
  • 控制指令路径
  • 控制线程语义

八、本质总结

软件设计追求确定性,其实是在追求:

对复杂性的完全掌控
C++提供的能力是:

  • 抽象
  • 同时保持可控
  • 同时保持性能
    这也是它区别于很多高级语言的根本点。

过程式设计与分层模块化架构风格(深度解析)

在大型系统早期(尤其是C语言主导时期),
过程式设计 + 分层模块化架构 是主流工程方法。
它解决的是一个核心问题:

如何在多人协作下控制复杂度?
可以抽象为:
S y s t e m = ∑ i = 1 n L a y e r i System = \sum_{i=1}^{n} Layer_i System=i=1nLayeri
并满足:
D e p e n d e n c y ( L i ) → L i − 1 Dependency(L_i) \rightarrow L_{i-1} Dependency(Li)Li1
即:
层间单向依赖

一、分层架构(Layered Architecture)

1⃣ 核心思想

系统按照职责划分为多个层级,例如:

应用层
业务逻辑层
服务层
基础设施层
操作系统层

规则:

  • 上层依赖下层
  • 下层不依赖上层
  • 禁止循环依赖
    形式化表达:
    ∀ i , ; L i  only depends on  L i − 1 \forall i, ; L_i \text{ only depends on } L_{i-1} i,;Li only depends on Li1
    这保证:
    N o   C i r c u l a r   D e p e n d e n c y No\ Circular\ Dependency No Circular Dependency

2⃣ 示例结构

// =========================
// 底层:数据访问层
// =========================
int read_from_disk() {
    return 42;  // 模拟底层数据读取
}
// =========================
// 上层:业务逻辑层
// =========================
int process_data() {
    int value = read_from_disk();  // 依赖下层
    return value * 2;
}

特点:

  • 上层依赖下层
  • 依赖方向清晰
  • 架构清晰

二、模块化设计(Modular Design)

模块化的核心目标:

将系统拆分为多个“功能单元”
可以表示为:
S y s t e m = M o d u l e 1 + M o d u l e 2 + ⋯ + M o d u l e n System = Module_1 + Module_2 + \cdots + Module_n System=Module1+Module2++Modulen
每个模块:

  • 独立开发
  • 通过接口通信
  • 可单独测试

问题:同层模块间依赖难以控制

例如:

Module A
Module B
Module C

如果:

A → B
B → C
C → A

就形成:
C i r c u l a r   D e p e n d e n c y Circular\ Dependency Circular Dependency
复杂度迅速上升:
C o u p l i n g ∝ n 2 Coupling \propto n^2 Couplingn2

三、模块内部的“过程式 + 全局变量”问题

在过程式时代,模块内部常见结构:

// module.cpp
// 全局变量(模块内部共享状态)
int counter = 0;
// 多个函数操作同一数据
void increment() {
    counter++;
}
void reset() {
    counter = 0;
}
int get() {
    return counter;
}

问题:

  • 状态隐式共享
  • 行为分散
  • 难以追踪状态变化来源
    本质是:
    S t a t e = G l o b a l State = Global State=Global
    而函数:
    F u n c t i o n ( S t a t e ) → M o d i f i e d   S t a t e Function(State) \rightarrow Modified\ State Function(State)Modified State
    这导致:
  • 模块内部高耦合
  • 难以并发扩展
  • 难以局部重构

四、架构风格总结

过程式分层模块架构的设计步骤:

1⃣ 分层次(Layering)

明确系统结构。

2⃣ 划模块(Modularization)

按功能拆分:

  • 网络模块
  • 存储模块
  • 计算模块

3⃣ 定接口(Interface)

接口定义:

// storage.h
int read_data();
void write_data(int value);

4⃣ 设计数据结构(数据建模)

例如:

struct User {
    int id;
    char name[32];
};

5⃣ 设计算法流程

用流程图或状态机表达:
I n p u t → P r o c e s s → O u t p u t Input \rightarrow Process \rightarrow Output InputProcessOutput

五、这种架构的优点

① 支撑大规模并行开发

因为:

  • 层次清晰
  • 模块边界明确
  • 接口固定
    团队可以:
  • A组开发模块A
  • B组开发模块B
    这是一种:

静态规划式开发

② 易于裁剪

删除某层或某模块即可裁剪功能。

③ 性能可控

由于过程式贴近机器:

  • 无隐藏对象开销
  • 无虚函数
  • 无异常栈展开

六、核心缺点

① 可复用性过粗

模块粒度太大。
例如:

整个存储模块

难以只复用其中一个算法。

② 响应变化能力弱

如果需求变化:

  • 数据结构改变
  • 可能影响整层
    例如:
struct User {
    int id;
};

改为:

struct User {
    int id;
    std::string email;
};

影响范围可能是:
I m p a c t ≈ A l l   L a y e r s Impact \approx All\ Layers ImpactAll Layers

③ 高耦合复杂度

如果:

  • 每层多个模块
  • 每模块多个全局变量
    潜在依赖规模为:
    O ( n × m ) O(n \times m) O(n×m)
    系统变大时:
    复杂度指数级上升。

七、为什么这种架构在历史上成功?

因为它:

  • 适合C语言
  • 适合操作系统
  • 适合嵌入式
  • 适合单机系统
    典型代表:
  • Unix内核
  • 早期数据库系统
  • 嵌入式固件

八、本质分析:静态规划式开发

这种架构假设:
需求基本稳定 需求基本稳定 需求基本稳定
因此:

  • 结构一次设计完成
  • 层级固定
  • 接口固定
    但现代系统特点是:
    C h a n g e   R a t e ↑ Change\ Rate \uparrow Change Rate
    变化频繁。
    这就导致:

过程式分层架构的响应能力下降。

九、总结

过程式 + 分层模块化架构:
优点:

  • 结构清晰
  • 可并行开发
  • 性能可控
  • 工程实践成熟
    缺点:
  • 模块内全局变量导致高耦合
  • 变化传播范围大
  • 粒度过粗
  • 动态扩展能力弱
    本质上:
    S t r u c t u r e   S t a b i l i t y ↑ ⇒ F l e x i b i l i t y ↓ Structure\ Stability \uparrow \Rightarrow Flexibility \downarrow Structure Stability↑⇒Flexibility

面向对象设计(Object-Oriented Design, OOD)

面向对象编程(OOP)的核心表达可以写成:
P r o g r a m = E n t i t i e s + R e l a t i o n s h i p s Program = Entities + Relationships Program=Entities+Relationships
或者更精确一点:
S y s t e m = O b j e c t s + R e l a t i o n s h i p s System = { Objects } + { Relationships } System=Objects+Relationships
与过程式:
P r o g r a m = D a t a + A l g o r i t h m Program = Data + Algorithm Program=Data+Algorithm
不同,OOP强调:

谁拥有数据?
谁负责行为?
对象之间如何协作?

一、面向对象的三大核心特性

① 封装(Encapsulation)

定义:

将数据与操作数据的行为绑定在一起,并隐藏内部实现细节。
数学表达:
O b j e c t = S t a t e + B e h a v i o r Object = State + Behavior Object=State+Behavior
并且:
S t a t e ∉ E x t e r n a l   D i r e c t   A c c e s s State \notin External\ Direct\ Access State/External Direct Access

示例:封装

#include <iostream>
class BankAccount {
private:
    int balance;  // 私有数据,外部不可直接访问
public:
    BankAccount(int initial) : balance(initial) {}
    void deposit(int amount) {
        balance += amount;  // 行为与数据绑定
    }
    int get_balance() const {
        return balance;  // 只读访问
    }
};
int main() {
    BankAccount acc(100);
    acc.deposit(50);
    std::cout << acc.get_balance() << std::endl;
}

优点:

  • 降低耦合
  • 保证数据一致性
  • 控制访问路径

② 继承(Inheritance)

继承表示:

子类“是一个”父类(is-a)
数学抽象:
S u b c l a s s ⊂ P a r e n t Subclass \subset Parent SubclassParent
或类型关系:
D e r i v e d ∈ B a s e Derived \in Base DerivedBase

示例:继承

#include <iostream>
// 父类
class Shape {
public:
    virtual double area() const = 0;  // 纯虚函数(接口)
};
// 子类
class Circle : public Shape {
private:
    double radius;
public:
    Circle(double r) : radius(r) {}
    double area() const override {
        return 3.14 * radius * radius;
    }
};

特点:

  • 代码复用
  • 类型扩展
  • 多态基础

③ 多态(Polymorphism)

多态核心:

相同接口,不同行为
数学表示:
f ( B a s e ∗ ) ⇒ D y n a m i c   D i s p a t c h f(Base*) \Rightarrow Dynamic\ Dispatch f(Base)Dynamic Dispatch
运行时决定调用哪个子类。

示例:多态

#include <iostream>
#include <memory>
class Shape {
public:
    virtual double area() const = 0;
    virtual ~Shape() = default;
};
class Rectangle : public Shape {
    double w, h;
public:
    Rectangle(double w_, double h_) : w(w_), h(h_) {}
    double area() const override {
        return w * h;
    }
};
void print_area(const Shape& s) {
    std::cout << s.area() << std::endl;  // 多态调用
}
int main() {
    Rectangle r(3, 4);
    print_area(r);  // 调用子类实现
}

本质:
I n t e r f a c e ≠ I m p l e m e n t a t i o n Interface \neq Implementation Interface=Implementation

二、Mermaid图关系解析

继承 (Inheritance)

继承 (Inheritance)

聚合 (Aggregation)

组合 (Composition)

«Top Class»

Class_Orange

«Parent/Target»

Class_LightGreen

«Component»

Class_Grey

«Subclass»

Class_Green_Left

«Subclass»

Class_Green_Right

你的类图表达了典型的OOP关系。

1⃣ 继承(Inheritance)

Class_Green_Left --|> Class_LightGreen
Class_Green_Right --|> Class_LightGreen

表示:
G r e e n _ L e f t , G r e e n _ R i g h t ⊂ L i g h t G r e e n Green\_Left, Green\_Right \subset LightGreen Green_Left,Green_RightLightGreen
即:

  • 子类继承父类
  • 共享接口
  • 可替换性(LSP原则)

2⃣ 聚合(Aggregation)

Class_Orange o-- Class_LightGreen

聚合表示:

“拥有”关系,但生命周期独立
数学表示:
A  has-a  B A \text{ has-a } B A has-a B
但:
D e s t r o y ( A ) ⇏ D e s t r o y ( B ) Destroy(A) \nRightarrow Destroy(B) Destroy(A)Destroy(B)

示例:聚合

class Engine {
public:
    void start() {}
};
class Car {
private:
    Engine* engine;  // 指针,不负责生命周期
public:
    Car(Engine* e) : engine(e) {}
};

3⃣ 组合(Composition)

Class_Green_Left *-- Class_Grey

组合表示:

强拥有关系,生命周期绑定
数学表达:
D e s t r o y ( A ) ⇒ D e s t r o y ( B ) Destroy(A) \Rightarrow Destroy(B) Destroy(A)Destroy(B)

示例:组合

class CPU {
};
class Computer {
private:
    CPU cpu;  // 成员对象,生命周期一致
};

三、面向对象的本质优势

① 降低耦合

过程式:
F u n c t i o n s → S h a r e d   G l o b a l   S t a t e Functions \rightarrow Shared\ Global\ State FunctionsShared Global State
OOP:
O b j e c t i → O w n   S t a t e Object_i \rightarrow Own\ State ObjectiOwn State
状态被局部化。

② 提高扩展性

新增功能只需:

class NewShape : public Shape { ... };

无需修改已有代码。
符合:

开闭原则(Open/Closed Principle)

③ 更贴近现实建模

现实世界:

  • 订单
  • 账户
  • 设备
    天然就是:
    E n t i t y + R e l a t i o n s h i p Entity + Relationship Entity+Relationship

四、OOP的代价

① 动态多态开销

虚函数调用:
I n d i r e c t   C a l l Indirect\ Call Indirect Call
需要:

  • vtable
  • 指针跳转

② 继承层次复杂化

如果:
D e p t h ↑ Depth \uparrow Depth
则理解成本上升。

③ 过度设计风险

小问题却设计:

  • 多层抽象
  • 多接口
  • 复杂继承树
    会降低可读性。

五、与过程式对比总结


特征过程式面向对象
核心数据 + 算法实体 + 关系
状态管理全局共享封装
扩展方式修改函数扩展子类
依赖控制较弱
建模能力偏技术偏领域

六、本质总结

面向对象的哲学是:

让对象对自己的状态负责
让系统由对象协作完成
可以抽象为:
C o m p l e x i t y   C o n t r o l = E n c a p s u l a t i o n + A b s t r a c t i o n + P o l y m o r p h i s m Complexity\ Control = Encapsulation + Abstraction + Polymorphism Complexity Control=Encapsulation+Abstraction+Polymorphism
它解决的是:
复杂系统中“状态失控”的问题

1⃣ Class Diagram(类图)

描述类、属性、方法以及类之间的关系(继承 / 组合 / 聚合 / 依赖)。

继承

聚合

Animal

+name: string

+eat()

Dog

+bark()

Owner

+name: string

说明:

  • --|> 表示继承
  • o-- 表示聚合
  • *-- 表示组合

2⃣ Object Diagram(对象图)

描述某一时刻的实例关系(运行时结构)。
Mermaid 没有专门对象图语法,通常用 classDiagram 表达实例:

owns

dog1

name = "Buddy"

owner1

name = "Alice"

表示:

  • 实例 dog1
  • 实例 owner1
  • owner1 拥有 dog1

3⃣ Component Diagram(组件图)

描述系统模块级结构。

UI Component

Service Component

Repository Component

Database

说明:

  • 表示模块依赖
  • 常用于系统架构设计

4⃣ Deployment Diagram(部署图)

描述系统物理部署结构。

Client Browser

Web Server

Application Server

Database Server

表示:

  • 客户端访问 Web 服务器
  • Web 调用应用服务器
  • 应用访问数据库

5⃣ Package Diagram(包图)

描述包之间的依赖关系。

UI Package

Service Package

Infrastructure Package

体现:

  • 分层架构
  • 单向依赖原则

6⃣ Composite Structure Diagram(复合结构图)

描述类内部结构组成。

Computer

+CPU cpu

+Memory memory

CPU

Memory

说明:

  • *-- 表示组合关系
  • CPU 和 Memory 生命周期依附 Computer

7⃣ Profile Diagram(UML Profile)

用于扩展 UML 元模型(定义 stereotype)
Mermaid 不支持 profile 语法,可用注释模拟:

«stereotype»

Controller

+handleRequest()

«stereotype»

Service

+process()

表示:

  • 使用 stereotype 扩展语义
  • 常用于框架建模(如 <>、<>)

总结对照表


图类型关注点Mermaid 实现方式
Class Diagram类型结构classDiagram
Object Diagram实例结构classDiagram模拟
Component Diagram模块结构graph
Deployment Diagram物理部署graph
Package Diagram包依赖graph
Composite Structure类内部结构classDiagram
Profile Diagram元模型扩展stereotype模拟

面向对象建模(Object-Oriented Modeling)如何通过“静态视图 + 动态视图”完整描述一个系统

可以理解为:

静态视图解决“系统是什么”
动态视图解决“系统如何运行”
下面做系统化、深入讲解。

一、面向对象建模的核心思想

面向对象建模的目标是:
系统 = 结构模型 + 行为模型 系统 = 结构模型 + 行为模型 系统=结构模型+行为模型
也可以理解为:
S y s t e m = S t a t i c   S t r u c t u r e + D y n a m i c   B e h a v i o r System = Static\ Structure + Dynamic\ Behavior System=Static Structure+Dynamic Behavior

二、静态视图(Structural View)

1⃣ 本质

静态视图描述:

  • 有哪些类
  • 类之间什么关系
  • 系统如何组织
  • 代码如何分层部署
    它回答的是:

“系统长什么样?”

2⃣ 常见结构类图(Structural Diagrams)

(1)Class Diagram —— 类图

最核心的结构图。
描述:

  • 属性
  • 方法
  • 继承
  • 组合
  • 聚合
  • 依赖
    示例代码:
// 一个典型类图对应的代码
class Engine {
public:
    void start() {}
};
class Car {
private:
    Engine engine;  // 组合关系(强拥有)
public:
    void run() {
        engine.start();
    }
};
  • Car 组合 Engine
  • Engine 生命周期依附 Car

(2)Object Diagram —— 对象图

类图是“类型结构”
对象图是“运行时实例结构”
示例:

Car car1;
Car car2;

对象图描述:

  • car1
  • car2
  • 它们各自拥有自己的 engine

(3)Component Diagram —— 组件图

强调模块级组织,而非类。
例如:

  • Auth Module
  • Payment Module
  • Logging Module
    适用于大型系统架构设计。

(4)Deployment Diagram —— 部署图

描述系统如何部署到物理环境:

  • Server A
  • Server B
  • 数据库
  • 网络
    例如:
    A p p   S e r v e r → D a t a b a s e   S e r v e r App\ Server \rightarrow Database\ Server App ServerDatabase Server

(5)Package Diagram —— 包图

用于描述代码包的依赖关系。

UI  →  Service  →  Repository

体现:

  • 单向依赖
  • 分层架构

(6)Composite Structure Diagram —— 复合结构图

强调类内部的组成关系。
例如:

class Computer {
    CPU cpu;
    Memory memory;
};

三、动态视图(Behavioral View)

1⃣ 本质

动态视图描述:

  • 对象如何交互
  • 状态如何变化
  • 消息如何传递
  • 系统如何运行
    回答的是:

“系统是如何工作的?”

2⃣ 行为类图(Behavioral Diagrams)

(1)Use Case Diagram —— 用例图

从用户视角出发:

  • 用户能做什么?
  • 系统提供什么能力?
    例如:
  • 用户登录
  • 下订单
  • 查询历史记录
    它定义的是:
    系统职责集合 = 功能 1 , 功能 2 , 功能 3 系统职责集合 = {功能1, 功能2, 功能3} 系统职责集合=功能1,功能2,功能3

(2)Sequence Diagram —— 时序图

描述对象间消息调用顺序。
例如:

User -> Controller -> Service -> Repository

调用链:
U s e r → C o n t r o l l e r → S e r v i c e → R e p o s i t o r y User \rightarrow Controller \rightarrow Service \rightarrow Repository UserControllerServiceRepository
代码对应:

controller.login();

内部:

void Controller::login() {
    service.authenticate();
}

(3)Communication Diagram —— 通信图

与时序图类似,但强调:

  • 对象间结构关系
  • 消息编号

(4)State Machine Diagram —— 状态机图

描述对象生命周期。
例如:
订单状态:
C r e a t e d → P a i d → S h i p p e d → C o m p l e t e d Created \rightarrow Paid \rightarrow Shipped \rightarrow Completed CreatedPaidShippedCompleted
代码示例:

enum class OrderState {
    Created,
    Paid,
    Shipped,
    Completed
};
class Order {
    OrderState state;
};

状态机的本质:
N e x t S t a t e = f ( C u r r e n t S t a t e , E v e n t ) NextState = f(CurrentState, Event) NextState=f(CurrentState,Event)

(5)Activity Diagram —— 活动图

类似流程图。
强调:

  • 并行
  • 分支
  • 条件判断
    例如:
验证账号 → 判断密码 → 成功 or 失败

(6)Interaction Overview Diagram —— 交互概览图

多个时序图的组合。

(7)Timing Diagram —— 时序变化图

强调时间维度上的状态变化。
常用于:

  • 实时系统
  • 嵌入式系统

1⃣ State Machine Diagram(状态机图)

pay()

ship()

deliver()

cancel()

refund()

Created

Paid

Shipped

Delivered

Cancelled

Refunded

✓ 描述订单状态流转

  • [*] = 初始状态
  • 事件触发状态变化

2⃣ Communication Diagram(通信图)

Mermaid 没有直接“通信图”,可以用 sequenceDiagram + 注释编号表示对象交互:

BankAPI PaymentService InventoryService OrderController User BankAPI PaymentService InventoryService OrderController User createOrder() checkStock() pay() requestPayment() paymentSuccess paymentConfirmed orderCompleted

✓ 强调对象之间的消息交互,按顺序编号

3⃣ Use Case Diagram(用例图)

Mermaid 支持用 graph TD 模拟用例图:

place order

pay

view order

manage products

User

Place Order

Pay

View Order

Admin

Manage Products

✓ 描述系统提供的功能和参与者,不关心内部实现

4⃣ Activity Diagram(活动图)

Yes

No

开始

填写订单

库存是否充足?

支付

提示库存不足

发货

结束

✓ 强调流程控制、条件分支、活动顺序

5⃣ Sequence Diagram(顺序图)

Payment Order Cart User Payment Order Cart User addItem() updateTotal() placeOrder() processPayment() paymentConfirmed orderSuccess

✓ 描述对象消息顺序和交互逻辑

6⃣ Timing Diagram(时序图)

<?plantuml 1.2026.2beta3?> Clock Request CPU Idle Fetching Processing Done Memory Ready Reading Writing 0 20 40 60 100 140

7⃣ Interaction Overview Diagram(交互概览图)

Mermaid 没有原生交互概览图,但可以用 graph TD +子图模拟:

RefundFlow

申请退款

审核

退款完成

PlaceOrderFlow

库存足够

库存不足

填写订单

检查库存

支付

提示库存不足

发货

✓ 强调 多个交互的整体流程,可以看作“活动图 +顺序图综合体”

四、静态 vs 动态的本质区别


维度静态视图动态视图
关注点类型实例
时间维度
描述内容结构行为
设计阶段架构设计业务流程设计
是否与代码强相关

五、面向对象建模的核心数学抽象

可以形式化理解为:

静态模型

M s = ( C , R ) M_s = (C, R) Ms=(C,R)

  • C C C = 类集合
  • R R R = 类之间的关系集合

动态模型

M d = ( O , E , S ) M_d = (O, E, S) Md=(O,E,S)

  • O O O = 对象集合
  • E E E = 事件集合
  • S S S = 状态转移函数

系统完整模型

S y s t e m = M s + M d System = M_s + M_d System=Ms+Md

六、工程实践意义

1⃣ 为什么需要静态视图?

  • 支撑大规模开发
  • 明确依赖
  • 便于裁剪
  • 方便代码生成

2⃣ 为什么需要动态视图?

  • 分析复杂业务流程
  • 发现隐藏耦合
  • 验证状态完整性
  • 推导并发问题

七、面向对象建模的局限

优点:

  • 结构清晰
  • 适合复杂系统
  • 强抽象能力
    缺点:
  • 静态结构稳定但变更成本高
  • 状态机爆炸问题
  • 继承层级过深易失控
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值