一个方法几千行的程序是如何产生的?

本文通过一个实际案例揭示了软件开发过程中代码膨胀的问题,并提出了基于业务流程与具体业务解耦的重构建议。
最近查看公司的代码,发现有很多体积很大的类,其中一些方法竟有几千行。

这些方法有些共同的特点:

包含大量巨大的if else嵌套。
伴随着大量的magicnumber。
存在大量的重复代码。
难以测试。
对于任何一个没有足够业务知识的人,完全不可读。

这些代码成长过程都很相似:

第一个人:把业务流程和业务代码封装在一个类里。业务不复杂,代码看起来还行。
第二个人:业务流程不变,但新增了业务需求。把第一个人的部分代码copy过来,修改几个业务代码,然后用一个大大的if else包裹起来。
第三个人:把第二个人的copy过来,也用if else包裹起来,增加一些magicnumber。
后面的人:重复前任的工作。
两年以后,就像我眼前看到的这份代码。 要避免这种情况,我觉得责任主要在第二人和第三个人。他们的工作不能仅是简单的copy,而应该重构。按照业务流程与具体业务解耦,业务之间解耦,独立业务聚合的原则:

首先,把以前代码中“业务流程部分”分离出来,作为流程处理类。
把具体业务抽象成接口,交给流程调用。
把每个业务独立分开,实现业务接口,不同的业务之间不存在耦合。
每个独立的业务,其业务逻辑代码只存在于一个class里。
这样后来人新增业务,会copy前人的实现类, 修改一些业务代码和逻辑。却不会形成如此巨大的方法。
# 普通文本型回答 下面我将**一步步解读这个大数阶乘程序的完整执流程**,从结构定义到主函数调用,逐层拆解,帮助你彻底理解每一部分的作用和运逻辑。 --- ### 🔹 第一步:定义链表节点 `Node` ```cpp struct Node { int data; // 存储0~999之间的数值 Node* next; // 指向下一个节点 Node(int d) : data(d), next(nullptr) {} }; ``` - **作用**:这是链表的基本单元。 - **`data`**:每个节点最多存三位数字(0~999),相当于“千进制”单位; - **`next`**:指针连接下一个节点,构成单向链表; - **构造函数**:创建节点时自动初始化数据,并将指针设为 `nullptr`。 > 📌 示例:若要存储 `123456`,则拆分为 `[456] → [123]`,低位在前。 --- ### 🔹 第二步:定义大整数类 `LargeNumber` ```cpp class LargeNumber { private: Node* head; // 头指针,指向最低三位(个位~百位) public: LargeNumber(); // 构造函数 ~LargeNumber(); // 析构函数 void multiply(int k); // 乘法函数 void display() const; // 输出函数 }; ``` - 整个大数运算被封装在这个类中,体现**面向对象的封装思想**; - 所有操作都通过成员函数完成,外部无法直接访问链表指针。 --- ### 🔹 第三步:构造函数 —— 初始化为 1 ```cpp LargeNumber::LargeNumber() { head = new Node(1); } ``` - 创建一个新节点,值为 1; - 因为阶乘 $n!$ 起始值是 1,所以初始状态就是 `1`; - 此时链表只有一个节点:`[1]`。 --- ### 🔹 第四步:析构函数 —— 安全释放内存 ```cpp ~LargeNumber() { Node* current = head; while (current != nullptr) { Node* temp = current; current = current->next; delete temp; } } ``` - 防止内存泄漏; - 依次遍历并删除所有节点; - 程序结束或对象销毁时自动调用。 --- ### 🔹 第五步:核心函数 `multiply(int k)` —— 实现高精度乘法 #### ✅ 功能说明: 将当前大数乘以一个普通整数 $k$(如 2, 3, ..., n)。 #### 分步执过程: ```cpp void multiply(int k) { Node* current = head; int carry = 0; ``` - 从头节点开始处理(即最低三位); - `carry` 用于保存进位。 ```cpp while (current != nullptr) { int product = current->data * k + carry; current->data = product % 1000; carry = product / 1000; current = current->next; } ``` - **遍历每个节点**: - 计算乘积:`product = 当前段 × k + 进位` - 取模保留后三位:`% 1000` - 进位 = 商:`/ 1000` - 示例:当前节点是 `999`,乘以 `2` → `1998` → 本节点变 `998`,进位 `1` ```cpp while (carry > 0) { Node* newNode = new Node(carry % 1000); carry /= 1000; Node* tail = head; while (tail->next != nullptr) { tail = tail->next; } tail->next = newNode; } ``` - **处理剩余进位**: - 如果还有进位,就需要新建节点继续存; - 例如:`carry = 1234` → 先存 `234`,再进位 `1` → 再建节点存 `1`; - 最终实现自动扩展链表长度。 --- ### 🔹 第六步:输出函数 `display()` —— 格式化打印结果 ```cpp void display() const { Node* reversed = nullptr; Node* current = head; while (current != nullptr) { Node* newNode = new Node(current->data); newNode->next = reversed; reversed = newNode; current = current->next; } ``` - 原始链表是**低位在前**,但输出需要**高位在前**; - 所以先构造一个**逆序链表**(类似栈操作); ```cpp if (reversed != nullptr) { cout << reversed->data; // 第一个不补零 Node* temp = reversed->next; while (temp != nullptr) { cout << setw(3) << setfill('0') << temp->data; temp = temp->next; } } cout << endl; ``` - 第一个数正常输出(如 `123`); - 后续每个数强制占三位,不足补零(如 `5` → `005`); - 使用 `<iomanip>` 的 `setw(3)` 和 `setfill('0')` 实现格式控制。 ```cpp while (reversed != nullptr) { Node* temp = reversed; reversed = reversed->next; delete temp; } ``` - 删除临时逆序链表,防止内存泄漏。 --- ### 🔹 第七步:主函数 `main()` —— 控制流程入口 ```cpp int main() { int n; cout << "请输入 n 的值:"; cin >> n; ``` - 用户输入 $n$,比如 `100`。 ```cpp if (n < 0) { cout << "负数没有阶乘!" << endl; return 1; } if (n == 0 || n == 1) { cout << n << "! = 1" << endl; return 0; } ``` - 边界判断:负数无阶乘;$0!=1$, $1!=1$。 ```cpp LargeNumber result; for (int i = 2; i <= n; ++i) { result.multiply(i); } ``` - 创建大整数对象 `result`,初始为 1; - 循环乘上 `2`, `3`, ..., `n`; - 每次调用 `multiply(i)` 更新内部链表。 ```cpp cout << n << "! = "; result.display(); ``` - 调用 `display()` 输出最终结果。 --- ### 🔹 总结:程序全流程示例(以 $n=5$ 为例) | 步骤 | 当前值 | 链表结构(低位在前) | 说明 | |------|--------|------------------------|------| | 初始化 | 1 | `[1]` | 构造函数设置 | | ×2 | 2 | `[2]` | 无进位 | | ×3 | 6 | `[6]` | 仍无进位 | | ×4 | 24 | `[24]` | 直接更新 | | ×5 | 120 | `[120]` | 结果仍小于1000 | 但如果 $n=100$,就会不断产生进位,链表逐渐变长,直到包含几十个节点。 --- ✅ **最终输出格式示例**: ``` 100! = 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000 ``` --- ### 🧩 关键设计理念回顾 | 设计点 | 目的 | |-------|------| | 千进制存储 | 减少节点数量,提高效率 | | 低位在前 | 方便进位向后扩展 | | 封装在类内 | 避免外部破坏结构 | | 动态扩展 | 支持任意大的阶乘 | | 格式化输出 | 保证结果正确显示 | --- 📌 **结论**:该程序通过模拟手算乘法 + 链表动态扩展 + 千进制压缩存储,成功突破了基本数据类型的限制,实现了对极大阶乘的精确计算。每一步都有清晰逻辑,结构严谨,适用于教学与工程实践。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值