在软件开发中,随着需求迭代,代码逐渐变得臃肿、耦合,难以维护——这就是所谓的“代码腐化”。它不仅降低开发效率,更会积累沉重的技术债务。今天,我们就通过一个具体的 C++ 案例,一步步演示如何运用经典的设计模式,将一团乱麻的函数重构成清晰、可扩展的优雅代码。
原始代码展示
我们先来看一个典型的“上帝函数”,它试图在一个函数 processOrder 中完成所有订单处理逻辑:
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
using namespace std;
void processOrder(const string& orderId, const vector<string>& items){
// 验证订单
if (orderId.empty()) {
cout << "订单ID不能为空" << endl;
return;
}
// 计算总价
double totalPrice = 0.0;
for (const auto& item : items) {
if (item == "book") {
totalPrice += 50.0;
} else if (item == "pen") {
totalPrice += 10.0;
} else if (item == "notebook") {
totalPrice += 20.0;
}
}
// 生成订单文件
ofstream orderFile("order_" + orderId + ".txt");
if (orderFile.is_open()) {
orderFile << "订单ID: " << orderId << endl;
orderFile << "商品列表: ";
for (const auto& item : items) {
orderFile << item << " ";
}
orderFile << endl;
orderFile << "总价: " << totalPrice << endl;
orderFile.close();
cout << "订单文件生成成功" << endl;
} else {
cout << "无法创建订单文件" << endl;
}
// 发送通知
cout << "订单已处理,通知客户" << endl;
}
int main(){
vector<string> items = {"book", "pen", "notebook"};
processOrder("20260203001", items);
return 0;
}
问题分析
这段代码虽然功能完整,但存在典型的“坏味道”:
- 单一职责原则违反:
processOrder 函数承担了验证订单、计算总价、生成文件和发送通知等多个职责,导致函数过于庞大复杂。
- 紧耦合:函数内部直接依赖于具体的商品定价逻辑和文件操作方式,难以进行单元测试和扩展。
- 可扩展性差:当新增商品类型时,需要修改
processOrder 函数中的条件判断,违反了开闭原则。
- 代码重复:如果系统中存在多个类似的订单处理逻辑,会导致大量重复代码。
- 错误处理不完善:函数中的错误处理比较简单,缺乏统一的错误处理机制。
重构方案设计
设计思路
针对上述问题,我们将采用分阶段的重构策略,逐步引入经典设计模式:
- 单一职责原则:将订单处理的不同职责拆分到不同的类中。
- 策略模式:将商品定价逻辑封装到策略类中,实现运行时切换。
- 工厂模式:根据不同的订单类型创建不同的订单处理器。
- 观察者模式:实现订单处理完成后的通知机制。
重构阶段规划
- 第一阶段:职责拆分,将订单处理的不同功能拆分到不同的类中。
- 第二阶段:应用策略模式,将商品定价逻辑抽象为策略接口。
- 第三阶段:应用工厂模式,实现订单处理器的动态创建。
- 第四阶段:应用观察者模式,实现订单处理完成后的通知机制。
- 第五阶段:代码优化与测试,确保重构后的代码功能正确且性能良好。
重构实施
第一阶段:职责拆分
首先,我们将原来混杂在单一函数中的职责,拆分到独立的类中。每个类只做一件事。
// 订单验证器
class OrderValidator {
public:
bool validate(const string& orderId){
if (orderId.empty()) {
cout << "订单ID不能为空" << endl;
return false;
}
return true;
}
};
// 价格计算器
class PriceCalculator {
public:
double calculate(const vector<string>& items){
double totalPrice = 0.0;
for (const auto& item : items) {
if (item == "book") {
totalPrice += 50.0;
} else if (item == "pen") {
totalPrice += 10.0;
} else if (item == "notebook") {
totalPrice += 20.0;
}
}
return totalPrice;
}
};
// 订单文件生成器
class OrderFileGenerator {
public:
bool generate(const string& orderId, const vector<string>& items, double totalPrice){
ofstream orderFile("order_" + orderId + ".txt");
if (orderFile.is_open()) {
orderFile << "订单ID: " << orderId << endl;
orderFile << "商品列表: ";
for (const auto& item : items) {
orderFile << item << " ";
}
orderFile << endl;
orderFile << "总价: " << totalPrice << endl;
orderFile.close();
cout << "订单文件生成成功" << endl;
return true;
} else {
cout << "无法创建订单文件" << endl;
return false;
}
}
};
// 通知发送器
class NotificationSender {
public:
void send(const string& orderId){
cout << "订单" << orderId << "已处理,通知客户" << endl;
}
};
// 订单处理器
class OrderProcessor {
private:
OrderValidator validator;
PriceCalculator calculator;
OrderFileGenerator fileGenerator;
NotificationSender sender;
public:
void process(const string& orderId, const vector<string>& items){
if (!validator.validate(orderId)) {
return;
}
double totalPrice = calculator.calculate(items);
if (!fileGenerator.generate(orderId, items, totalPrice)) {
return;
}
sender.send(orderId);
}
};
int main(){
vector<string> items = {"book", "pen", "notebook"};
OrderProcessor processor;
processor.process("20260203001", items);
return 0;
}
重构效果:通过职责拆分,每个类都变得小巧且目标明确。OrderProcessor 现在只负责协调,符合单一职责原则,代码的可读性和可维护性显著提高。单元测试也变得容易,你可以单独测试 PriceCalculator 或 OrderValidator。
第二阶段:应用策略模式
价格计算器中仍存在硬编码的条件判断。我们使用策略模式将其抽象。
// 定价策略接口
class PricingStrategy {
public:
virtual double calculatePrice(const string& item) = 0;
virtual ~PricingStrategy() = default;
};
// 图书定价策略
class BookPricingStrategy : public PricingStrategy {
public:
double calculatePrice(const string& item) override {
return 50.0;
}
};
// 笔定价策略
class PenPricingStrategy : public PricingStrategy {
public:
double calculatePrice(const string& item) override {
return 10.0;
}
};
// 笔记本定价策略
class NotebookPricingStrategy : public PricingStrategy {
public:
double calculatePrice(const string& item) override {
return 20.0;
}
};
// 价格计算器
class PriceCalculator {
private:
map<string, unique_ptr<PricingStrategy>> strategies;
public:
PriceCalculator() {
strategies["book"] = make_unique<BookPricingStrategy>();
strategies["pen"] = make_unique<PenPricingStrategy>();
strategies["notebook"] = make_unique<NotebookPricingStrategy>();
}
double calculate(const vector<string>& items){
double totalPrice = 0.0;
for (const auto& item : items) {
if (strategies.find(item) != strategies.end()) {
totalPrice += strategies[item]->calculatePrice(item);
}
}
return totalPrice;
}
};
重构效果:定价逻辑被封装到独立的策略类中。现在,如果要新增一种商品(例如“eraser”),你只需要创建一个新的 EraserPricingStrategy 类并在 PriceCalculator 的构造器中注册它,无需修改 PriceCalculator::calculate 方法的任何现有代码。这完美遵循了开闭原则,系统扩展性大大增强。
第三阶段:应用工厂模式
系统可能需要支持不同类型的订单(如普通订单、加急订单)。我们可以用工厂模式来创建对应的处理器。
// 订单处理器接口
class OrderProcessor {
public:
virtual void process(const string& orderId, const vector<string>& items) = 0;
virtual ~OrderProcessor() = default;
};
// 普通订单处理器
class NormalOrderProcessor : public OrderProcessor {
private:
OrderValidator validator;
PriceCalculator calculator;
OrderFileGenerator fileGenerator;
NotificationSender sender;
public:
void process(const string& orderId, const vector<string>& items) override {
if (!validator.validate(orderId)) {
return;
}
double totalPrice = calculator.calculate(items);
if (!fileGenerator.generate(orderId, items, totalPrice)) {
return;
}
sender.send(orderId);
}
};
// 加急订单处理器
class ExpressOrderProcessor : public OrderProcessor {
private:
OrderValidator validator;
PriceCalculator calculator;
OrderFileGenerator fileGenerator;
NotificationSender sender;
public:
void process(const string& orderId, const vector<string>& items) override {
if (!validator.validate(orderId)) {
return;
}
double totalPrice = calculator.calculate(items) * 1.2; // 加急订单加价20%
if (!fileGenerator.generate(orderId, items, totalPrice)) {
return;
}
sender.send(orderId + " (加急)");
}
};
// 订单处理器工厂
class OrderProcessorFactory {
public:
static unique_ptr<OrderProcessor> createProcessor(const string& orderType){
if (orderType == "normal") {
return make_unique<NormalOrderProcessor>();
} else if (orderType == "express") {
return make_unique<ExpressOrderProcessor>();
}
return nullptr;
}
};
int main(){
vector<string> items = {"book", "pen", "notebook"};
// 创建普通订单处理器
auto normalProcessor = OrderProcessorFactory::createProcessor("normal");
if (normalProcessor) {
normalProcessor->process("20260203001", items);
}
// 创建加急订单处理器
auto expressProcessor = OrderProcessorFactory::createProcessor("express");
if (expressProcessor) {
expressProcessor->process("20260203002", items);
}
return 0;
}
重构效果:客户端(main函数)不再需要知道 NormalOrderProcessor 或 ExpressOrderProcessor 的具体实现细节,它只依赖于抽象的 OrderProcessor 接口和 OrderProcessorFactory。这种松耦合的设计使得增加新的订单类型(如“团购订单”)变得非常容易,只需新增一个处理器类并扩展工厂方法,而不会影响现有客户端代码。
第四阶段:应用观察者模式
最后,我们改造通知机制。原来的 NotificationSender 是紧耦合的,我们使用观察者模式来实现灵活、可扩展的通知系统。
// 观察者接口
class OrderObserver {
public:
virtual void onOrderProcessed(const string& orderId) = 0;
virtual ~OrderObserver() = default;
};
// 邮件通知观察者
class EmailNotificationObserver : public OrderObserver {
public:
void onOrderProcessed(const string& orderId) override {
cout << "发送邮件通知:订单" << orderId << "已处理" << endl;
}
};
// 短信通知观察者
class SMSNotificationObserver : public OrderObserver {
public:
void onOrderProcessed(const string& orderId) override {
cout << "发送短信通知:订单" << orderId << "已处理" << endl;
}
};
// 订单处理器接口
class OrderProcessor {
public:
virtual void process(const string& orderId, const vector<string>& items) = 0;
virtual void addObserver(unique_ptr<OrderObserver> observer) = 0;
virtual ~OrderProcessor() = default;
};
// 普通订单处理器
class NormalOrderProcessor : public OrderProcessor {
private:
OrderValidator validator;
PriceCalculator calculator;
OrderFileGenerator fileGenerator;
vector<unique_ptr<OrderObserver>> observers;
public:
void process(const string& orderId, const vector<string>& items) override {
if (!validator.validate(orderId)) {
return;
}
double totalPrice = calculator.calculate(items);
if (!fileGenerator.generate(orderId, items, totalPrice)) {
return;
}
// 通知所有观察者
for (const auto& observer : observers) {
observer->onOrderProcessed(orderId);
}
}
void addObserver(unique_ptr<OrderObserver> observer) override {
observers.push_back(move(observer));
}
};
int main(){
vector<string> items = {"book", "pen", "notebook"};
// 创建普通订单处理器 (假设工厂模式已集成)
auto normalProcessor = OrderProcessorFactory::createProcessor("normal");
if (normalProcessor) {
// 添加观察者
normalProcessor->addObserver(make_unique<EmailNotificationObserver>());
normalProcessor->addObserver(make_unique<SMSNotificationObserver>());
normalProcessor->process("20260203001", items);
}
return 0;
}
重构效果:通知系统与订单处理逻辑彻底解耦。OrderProcessor 不再关心谁接收通知、如何通知,它只负责在适当的时候发出事件。你可以动态地添加或移除观察者(例如新增一个“企业微信通知观察者”),而订单处理的核心代码纹丝不动。这再次体现了开闭原则的强大威力。
总结
回顾这次重构之旅,我们从一个职责混乱、高度耦合的“上帝函数”出发,通过分步应用单一职责原则、策略模式、工厂模式和观察者模式,最终构建了一个职责清晰、松耦合、易扩展的C++系统。
重构的核心价值不在于让代码立刻多做多少事,而在于让代码在未来更容易应对变化。每一次拆分、每一个接口的引入,都是在为代码的可维护性和可扩展性投资。掌握这些设计原则与模式,并将其融入日常的编码与重构实践中,是每一位追求卓越的开发者必经之路。
希望这个详细的案例能为你提供清晰的代码重构思路。如果你对如何在复杂系统中进行更大规模的重构,或者对其他设计模式的应用有疑问,欢迎在云栈社区与更多开发者一起交流探讨。
