冗赘的元素(Lazy Element):坏味道识别与重构实战指南
冗赘的元素(Lazy Element):坏味道识别与重构实战指南24种代码坏味道系列 · 第14篇
1. 开篇场景你是否遇到过这样的代码:一个 StringWrapper 类只是简单地包装了 std::string,没有添加任何额外功能;一个 getName 方法只是简单地返回 name.getValue(),没有添加任何逻辑?
1234567891011121314class StringWrapper { std::string value;public: std::string getValue() { return value; } void setValue(const std::string& str) { value = str; }};class BadExample { StringWrapper name;public: std::string getName() { return name.getValue(); // 只是简单 ...
循环语句(Loops):坏味道识别与重构实战指南
循环语句(Loops):坏味道识别与重构实战指南24种代码坏味道系列 · 第13篇
1. 开篇场景你是否遇到过这样的代码:使用 for 循环过滤、转换、求和、查找,虽然功能正确,但代码冗长且不够声明式?
123456789std::vector<int> filterEvenNumbers(const std::vector<int>& numbers) { std::vector<int> result; for (int i = 0; i < numbers.size(); i++) { if (numbers[i] % 2 == 0) { result.push_back(numbers[i]); } } return result;}
这就是循环语句的典型症状。使用命令式循环处理集合,虽然可以工作,但代码冗长且不够声明式。现代C++提供了丰富的STL算法,可以更简洁、更安全地处理集合操作。
...
重复的switch(Repeated Switches):坏味道识别与重构实战指南
重复的switch(Repeated Switches):坏味道识别与重构实战指南24种代码坏味道系列 · 第12篇
1. 开篇场景你是否遇到过这样的代码:相同的 switch 语句在多个地方重复出现,每次添加新的分支时,都需要在所有地方同步修改?
12345678910111213141516double calculateDiscount(UserType type, double price) { switch (type) { case UserType::REGULAR: return price * 0.0; case UserType::VIP: return price * 0.1; case UserType::PREMIUM: return price * 0.2; }}int getMaxItems(UserType type) { // 相同的 switch 逻辑重复了 switch (type) { case User ...
基本类型偏执(Primitive Obsession):坏味道识别与重构实战指南
基本类型偏执(Primitive Obsession):坏味道识别与重构实战指南24种代码坏味道系列 · 第11篇
1. 开篇场景你是否遇到过这样的代码:使用 std::string 表示邮箱地址,但没有验证;使用 std::string 表示电话号码,但没有验证;使用 int 表示年龄,但没有范围检查?
123456789void sendEmail(std::string email, std::string subject, std::string body) { // 使用 string 表示邮箱,但没有验证 std::cout << "Sending email to: " << email << std::endl;}void setAge(int age) { // age 可能是负数或很大的数,但没有范围检查 std::cout << "Age set to: " << age << std::endl ...
数据泥团(Data Clumps):坏味道识别与重构实战指南
数据泥团(Data Clumps):坏味道识别与重构实战指南24种代码坏味道系列 · 第10篇
1. 开篇场景你是否遇到过这样的代码:firstName 和 lastName 总是成对出现,street、city 和 zipCode 也总是同时传递,但它们却作为独立的参数在多个函数间传递?
123456789101112void createUser(std::string firstName, std::string lastName, std::string street, std::string city, std::string zipCode) { // firstName, lastName 总是成对出现 // street, city, zipCode 总是成对出现}void updateUser(std::string firstName, std::string lastName, std::string street, std::string ...
依恋情结(Feature Envy):坏味道识别与重构实战指南
依恋情结(Feature Envy):坏味道识别与重构实战指南24种代码坏味道系列 · 第9篇
1. 开篇场景你是否遇到过这样的方法:它在一个类中,但大部分时间都在访问另一个类的数据,就像一个人住在A城市,但每天都要跑到B城市去工作?
123456789class OrderCalculator {public: double calculateTotal(Order& order) { // 这个方法频繁访问 Order 的字段,应该属于 Order 类 double discountedPrice = order.basePrice * (1.0 - order.discount); double total = discountedPrice + (discountedPrice * order.tax); return total; }};
这就是依恋情结的典型症状。一个方法过度使用另一个类的数据,应该移到那个类中。方法对另一个类的”依恋”超过了对自己所在类 ...
霰弹式修改(Shotgun Surgery):坏味道识别与重构实战指南
霰弹式修改(Shotgun Surgery):坏味道识别与重构实战指南24种代码坏味道系列 · 第8篇
1. 开篇场景你是否遇到过这样的场景:需要修改用户验证规则(如最小长度从3改为5),却发现需要在 UserService、UserController、UserRepository 等多个类中逐一修改相同的验证逻辑?
123456789101112131415161718192021222324// 需要在多个类中修改相同的验证逻辑class UserService { void createUser(const std::string& username) { if (username.length() < 3) { // 需要修改这里 // ... } }};class UserController { void registerUser(const std::string& username) { ...
发散式变化(Divergent Change):坏味道识别与重构实战指南
发散式变化(Divergent Change):坏味道识别与重构实战指南24种代码坏味道系列 · 第7篇
1. 开篇场景你是否遇到过这样的类:当数据库格式改变时,需要修改它;当XML格式改变时,需要修改它;当计算逻辑改变时,也需要修改它?一个类因为多种不同的原因需要修改,就像一台多功能机器,任何一个功能出问题都需要整台机器停下来维修。
12345678910111213class BadExample { // 原因1:数据库格式改变 → 修改这里 std::string toDatabaseFormat() const { /* ... */ } // 原因2:XML格式改变 → 修改这里 std::string toXMLFormat() const { /* ... */ } // 原因3:计算逻辑改变 → 修改这里 double calculateTax() const { /* ... */ } // 原因4:显示格式改变 → 修改这里 ...
可变数据(Mutable Data):坏味道识别与重构实战指南
可变数据(Mutable Data):坏味道识别与重构实战指南24种代码坏味道系列 · 第6篇
1. 开篇场景你是否遇到过这样的代码:类的公共字段 balance 可以被任何地方直接修改,导致账户余额可能变成负数,或者被意外设置为异常值?
123456789101112class BadExample {public: int balance = 1000; // 公共字段,任何地方都可以修改 void withdraw(int amount) { balance -= amount; // 没有验证,可能变成负数 }};// 任何地方都可以直接修改BadExample account;account.balance = -1000; // 直接修改,导致数据不一致
这就是可变数据的典型症状。数据没有受到保护,可以在任何地方被修改,就像银行金库没有锁,任何人都可以随意存取现金。
当你需要确保数据的一致性时(如余额不能为负数),公共可变数据会让你无法控制。更糟糕的是,当bug出现时,你很难追踪是哪 ...
全局数据(Global Data):坏味道识别与重构实战指南
全局数据(Global Data):坏味道识别与重构实战指南24种代码坏味道系列 · 第5篇
1. 开篇场景你是否遇到过这样的代码:多个函数都在使用全局变量 globalUserName、globalUserCount,当你修改一个函数时,不知道会不会影响其他函数,就像在一个共享的记事本上写字,不知道其他人是否也在同时修改?
12345678910111213141516std::string globalUserName;int globalUserCount = 0;bool globalIsLoggedIn = false;void login(std::string username) { globalUserName = username; globalUserCount++; globalIsLoggedIn = true;}void someOtherFunction() { // 直接使用全局变量,不知道是谁设置的 if (globalIsLoggedIn) { // 处理逻辑... ...
