【Linux C/C++开发】第14章:综合项目与实践 - 从理论到现实的跨越
·
第14章:综合项目与实践 - 从理论到现实的跨越
14.1 软件设计的核心思想
14.1.1 SOLID原则 - 优秀代码的基石
想象你在经营一家餐厅:
单一职责原则(SRP):一个厨师只负责一个菜系
- 不好的做法:一个厨师既做中餐又做西餐还管采购
- 好的做法:中餐厨师专门做中餐,西餐厨师专门做西餐,采购员专门负责采购
// 违反SRP:一个类承担太多职责
class StudentManager {
public:
void addStudent(const Student& s) { /* ... */ }
void saveToFile(const std::string& filename) { /* ... */ } // 数据持久化
void printReport() { /* ... */ } // 报表生成
void sendEmail(const std::string& email) { /* ... */ } // 邮件发送
};
// 遵循SRP:每个类只有一个职责
class StudentService {
public:
void addStudent(const Student& s) { /* ... */ }
};
class StudentRepository {
public:
void saveToFile(const std::string& filename) { /* ... */ }
};
class ReportGenerator {
public:
void printReport() { /* ... */ }
};
class EmailService {
public:
void sendEmail(const std::string& email) { /* ... */ }
};
开闭原则(OCP):对扩展开放,对修改关闭
- 现实例子:餐厅的菜单可以新增菜品,但不需要改变现有的烹饪流程
// 违反OCP:新增支付方式需要修改原有代码
class PaymentProcessor {
public:
void processPayment(const std::string& type, double amount) {
if (type == "cash") {
// 现金支付处理
} else if (type == "credit") {
// 信用卡支付处理
} else if (type == "alipay") { // 新增支付宝需要修改代码
// 支付宝处理
}
}
};
// 遵循OCP:通过抽象扩展功能
class PaymentMethod {
public:
virtual void pay(double amount) = 0;
virtual ~PaymentMethod() = default;
};
class CashPayment : public PaymentMethod {
public:
void pay(double amount) override { /* 现金支付 */ }
};
class CreditPayment : public PaymentMethod {
public:
void pay(double amount) override { /* 信用卡支付 */ }
};
class AlipayPayment : public PaymentMethod { // 新增支付方式,无需修改原有代码
public:
void pay(double amount) override { /* 支付宝支付 */ }
};
class PaymentProcessor {
public:
void processPayment(PaymentMethod* method, double amount) {
method->pay(amount);
}
};
14.1.2 设计模式 - 前人总结的智慧
设计模式就像建筑模式:不是具体的建筑图纸,而是解决常见问题的通用方法。
创建型模式(对象怎么来):
- 工厂方法:就像不同品牌的汽车工厂,每个工厂专门生产自己的车型
- 建造者:就像装修房子,可以按不同套餐(简约、豪华、欧式)来装修
- 单例:就像公司只有一个总经理,所有人找的都是同一个人
// 工厂方法模式:不同类型的文档创建器
class DocumentCreator {
public:
virtual std::unique_ptr<Document> createDocument() = 0;
virtual ~DocumentCreator() = default;
};
class PDFCreator : public DocumentCreator {
public:
std::unique_ptr<Document> createDocument() override {
return std::make_unique<PDFDocument>();
}
};
class WordCreator : public DocumentCreator {
public:
std::unique_ptr<Document> createDocument() override {
return std::make_unique<WordDocument>();
}
};
// 建造者模式:复杂对象的逐步构建
class ComputerBuilder {
protected:
Computer computer;
public:
virtual void buildCPU() = 0;
virtual void buildMemory() = 0;
virtual void buildStorage() = 0;
Computer getResult() { return computer; }
};
class GamingComputerBuilder : public ComputerBuilder {
public:
void buildCPU() override { computer.setCPU("Intel i9"); }
void buildMemory() override { computer.setMemory("32GB DDR4"); }
void buildStorage() override { computer.setStorage("1TB SSD"); }
};
class OfficeComputerBuilder : public ComputerBuilder {
public:
void buildCPU() override { computer.setCPU("Intel i5"); }
void buildMemory() override { computer.setMemory("8GB DDR4"); }
void buildStorage() override { computer.setStorage("256GB SSD"); }
};
结构型模式(对象怎么组合):
- 适配器:就像电源转换器,让不同标准的插头能正常使用
- 装饰器:就像给手机贴膜、加壳,在保持原有功能的基础上增加新功能
- 代理:就像房产中介,帮你处理买房的复杂流程
// 适配器模式:让不兼容的接口能够协同工作
class LegacyPrinter {
public:
void printDocument(const std::string& text) {
std::cout << "Legacy printing: " << text << std::endl;
}
};
class ModernPrinter {
public:
virtual void print(const std::string& document) = 0;
virtual ~ModernPrinter() = default;
};
class PrinterAdapter : public ModernPrinter {
private:
LegacyPrinter legacyPrinter;
public:
void print(const std::string& document) override {
legacyPrinter.printDocument(document);
}
};
// 装饰器模式:动态添加功能
class Coffee {
public:
virtual std::string getDescription() const = 0;
virtual double getCost() const = 0;
virtual ~Coffee() = default;
};
class SimpleCoffee : public Coffee {
public:
std::string getDescription() const override {
return "Simple Coffee";
}
double getCost() const override {
return 2.0;
}
};
class CoffeeDecorator : public Coffee {
protected:
std::unique_ptr<Coffee> coffee;
public:
explicit CoffeeDecorator(std::unique_ptr<Coffee> c)
: coffee(std::move(c)) {}
};
class MilkDecorator : public CoffeeDecorator {
public:
using CoffeeDecorator::CoffeeDecorator;
std::string getDescription() const override {
return coffee->getDescription() + ", with milk";
}
double getCost() const override {
return coffee->getCost() + 0.5;
}
};
class SugarDecorator : public CoffeeDecorator {
public:
using CoffeeDecorator::CoffeeDecorator;
std::string getDescription() const override {
return coffee->getDescription() + ", with sugar";
}
double getCost() const override {
return coffee->getCost() + 0.2;
}
};
行为型模式(对象怎么协作):
- 观察者:就像微信公众号,你关注后,作者发新文章你会收到通知
- 策略:就像导航软件,可以选择"最快路线"、“最短路线”、"避免拥堵"等不同策略
- 模板方法:就像做菜的步骤框架,具体的调料和火候由子类决定
// 观察者模式:发布-订阅机制
class Subject {
private:
std::vector<Observer*> observers;
public:
void attach(Observer* observer) {
observers.push_back(observer);
}
void detach(Observer* observer) {
observers.erase(
std::remove(observers.begin(), observers.end(), observer),
observers.end()
);
}
void notify(const std::string& message) {
for (auto* observer : observers) {
observer->update(message);
}
}
};
class Observer {
public:
virtual void update(const std::string& message) = 0;
virtual ~Observer() = default;
};
class EmailObserver : public Observer {
private:
std::string email;
public:
explicit EmailObserver(const std::string& e) : email(e) {}
void update(const std::string& message) override {
std::cout << "Sending email to " << email << ": " << message << std::endl;
}
};
class SMSObserver : public Observer {
private:
std::string phone;
public:
explicit SMSObserver(const std::string& p) : phone(p) {}
void update(const std::string& message) override {
std::cout << "Sending SMS to " << phone << ": " << message << std::endl;
}
};
// 策略模式:算法族的可互换性
class PaymentStrategy {
public:
virtual bool pay(double amount) = 0;
virtual ~PaymentStrategy() = default;
};
class CreditCardStrategy : public PaymentStrategy {
private:
std::string cardNumber;
std::string cvv;
public:
CreditCardStrategy(const std::string& card, const std::string& cvv)
: cardNumber(card), cvv(cvv) {}
bool pay(double amount) override {
std::cout << "Paid " << amount << " using credit card " << cardNumber << std::endl;
return true;
}
};
class PayPalStrategy : public PaymentStrategy {
private:
std::string email;
std::string password;
public:
PayPalStrategy(const std::string& email, const std::string& pwd)
: email(email), password(pwd) {}
bool pay(double amount) override {
std::cout << "Paid " << amount << " using PayPal account " << email << std::endl;
return true;
}
};
class ShoppingCart {
private:
std::vector<Item> items;
std::unique_ptr<PaymentStrategy> paymentStrategy;
public:
void addItem(const Item& item) {
items.push_back(item);
}
void setPaymentStrategy(std::unique_ptr<PaymentStrategy> strategy) {
paymentStrategy = std::move(strategy);
}
double calculateTotal() const {
double total = 0.0;
for (const auto& item : items) {
total += item.getPrice();
}
return total;
}
bool checkout() {
if (!paymentStrategy) {
std::cout << "Payment method not set!" << std::endl;
return false;
}
double total = calculateTotal();
return paymentStrategy->pay(total);
}
};
14.2 项目管理实践
14.2.1 需求分析 - 搞清楚要做什么
需求获取就像点菜:
- 访谈:直接问顾客想吃什么
- 问卷:给菜单让顾客勾选
- 观察:看顾客平时都点什么
- 原型:先做小样让顾客尝尝
需求分类:
- 功能性需求:系统必须提供的功能(就像菜品必须有味道)
- 非功能性需求:性能、安全性、可用性等(就像上菜速度、卫生条件、服务态度)
- 约束条件:预算、时间、技术限制(就像厨房设备、厨师技能、营业时间)
// 需求文档的结构化表示
struct SystemRequirements {
struct FunctionalRequirements {
std::vector<std::string> must_have; // 必须有
std::vector<std::string> should_have; // 应该有
std::vector<std::string> nice_to_have; // 可以有
} functional;
struct NonFunctionalRequirements {
int max_response_time_ms; // 最大响应时间
int max_concurrent_users; // 最大并发用户数
std::string security_level; // 安全级别
std::string availability_sla; // 可用性要求
} non_functional;
struct Constraints {
std::string budget_range; // 预算范围
std::string deadline; // 截止时间
std::vector<std::string> tech_stack; // 技术栈限制
} constraints;
};
14.2.2 开发模式选择
开发模式就像做菜方式:
瀑布模型:传统做法,一步一步来
- 就像做复杂宴席:先定菜单→采购→预处理→烹饪→上菜
- 适合:需求明确、变更少的项目
敏捷开发:小步快跑,快速迭代
- 就像做自助餐:先做几个菜让大家尝尝,根据反馈调整
- 适合:需求不明确、需要快速验证的项目
// 敏捷开发的迭代管理
class Sprint {
private:
int sprint_number;
std::string goal;
std::vector<UserStory> stories;
std::chrono::system_clock::time_point start_date;
std::chrono::system_clock::time_point end_date;
public:
struct UserStory {
std::string id;
std::string description;
int story_points;
std::string status; // "todo", "in_progress", "done"
};
void addStory(const UserStory& story) {
stories.push_back(story);
}
double getCompletedPercentage() const {
int done_count = std::count_if(stories.begin(), stories.end(),
[](const UserStory& s) { return s.status == "done"; });
return stories.empty() ? 0.0 : (double)done_count / stories.size() * 100.0;
}
int getTotalStoryPoints() const {
return std::accumulate(stories.begin(), stories.end(), 0,
[](int sum, const UserStory& s) { return sum + s.story_points; });
}
};
14.2.3 风险管理 - 提前识别问题
风险管理就像开车时的风险预判:
风险识别:
- 技术风险:新技术不成熟、性能问题(就像新车性能不了解)
- 进度风险:时间估计不准、需求变更(就像路况变化)
- 人员风险:关键人员离职、技能不足(就像司机突然不舒服)
- 外部风险:第三方服务故障、政策变化(就像天气突变)
// 风险管理系统
class Risk {
private:
std::string description;
int probability; // 1-10,发生概率
int impact; // 1-10,影响程度
std::string mitigation_strategy;
std::string owner;
public:
int getRiskScore() const { return probability * impact; }
std::string getSeverity() const {
int score = getRiskScore();
if (score >= 60) return "HIGH";
if (score >= 30) return "MEDIUM";
return "LOW";
}
bool needsAttention() const {
return getRiskScore() >= 40; // 高分风险需要关注
}
};
class RiskManager {
private:
std::vector<Risk> risks;
public:
void addRisk(const Risk& risk) {
risks.push_back(risk);
}
std::vector<Risk> getHighRisks() const {
std::vector<Risk> high_risks;
std::copy_if(risks.begin(), risks.end(),
std::back_inserter(high_risks),
[](const Risk& r) { return r.needsAttention(); });
std::sort(high_risks.begin(), high_risks.end(),
[](const Risk& a, const Risk& b) {
return a.getRiskScore() > b.getRiskScore();
});
return high_risks;
}
void generateRiskReport() const {
auto high_risks = getHighRisks();
std::cout << "=== 风险报告 ===" << std::endl;
std::cout << "高风险数量: " << high_risks.size() << std::endl;
for (const auto& risk : high_risks) {
std::cout << "风险: " << risk.getSeverity() << " (评分: "
<< risk.getRiskScore() << ")" << std::endl;
}
}
};
14.3 编码实践与质量保障
14.3.1 代码质量 - 写人能读懂的代码
代码质量就像菜品质量:
- 正确性:菜要做对,不能顾客点宫保鸡丁你给回锅肉
- 可读性:菜要摆盘美观,让人有食欲
- 可维护性:菜谱要清晰,其他厨师能看懂
- 效率:做菜速度要合理,不能让人等太久
- 可靠性:每次做的味道要一致
// 不好的代码:难以理解,难以维护
class S {
private:
std::vector<std::string> d;
public:
void a(const std::string& s) {
d.push_back(s);
}
std::string g(int i) {
return d[i];
}
int c() {
return d.size();
}
};
// 好的代码:清晰易懂,易于维护
class StudentRepository {
private:
std::vector<std::string> student_names;
public:
void addStudent(const std::string& name) {
student_names.push_back(name);
}
std::string getStudentName(int index) const {
if (index >= 0 && index < student_names.size()) {
return student_names[index];
}
throw std::out_of_range("Student index out of range");
}
int getStudentCount() const {
return student_names.size();
}
};
14.3.2 重构技巧 - 改善既有代码
重构就像厨房改造:
- 小步前进:一次只改一点,避免大动干戈
- 保持行为不变:菜的味道不能变,只是做法更高效
- 频繁测试:每改一步都要尝尝味道
- 逐步改进:通过多次小的改善达到大的提升
// 重构前:方法过长,职责不清
void processStudentData() {
// 读取数据(20行代码)
std::ifstream file("students.txt");
std::vector<Student> students;
std::string line;
while (std::getline(file, line)) {
// 解析CSV格式...
// 创建学生对象...
// 添加到集合...
}
// 计算统计(30行代码)
int total_age = 0;
int count = 0;
for (const auto& student : students) {
total_age += student.getAge();
count++;
}
double average_age = count > 0 ? static_cast<double>(total_age) / count : 0;
// 生成报告(25行代码)
std::ofstream report("report.txt");
report << "Student Statistics Report\n";
report << "=========================\n";
report << "Total students: " << count << "\n";
report << "Average age: " << average_age << "\n";
// 更多报告内容...
}
// 重构后:方法短小,职责明确
class StudentProcessor {
private:
std::vector<Student> students;
std::vector<Student> loadStudentsFromFile(const std::string& filename) {
std::vector<Student> result;
std::ifstream file(filename);
std::string line;
while (std::getline(file, line)) {
Student student = parseStudentFromCSV(line);
result.push_back(student);
}
return result;
}
Student parseStudentFromCSV(const std::string& csv_line) {
std::istringstream iss(csv_line);
std::string name, age_str;
std::getline(iss, name, ',');
std::getline(iss, age_str, ',');
int age = std::stoi(age_str);
return Student(name, age);
}
struct Statistics {
int total_students;
double average_age;
int min_age;
int max_age;
};
Statistics calculateStatistics(const std::vector<Student>& students) {
if (students.empty()) {
return {0, 0.0, 0, 0};
}
int total_age = 0;
int min_age = students[0].getAge();
int max_age = students[0].getAge();
for (const auto& student : students) {
int age = student.getAge();
total_age += age;
min_age = std::min(min_age, age);
max_age = std::max(max_age, age);
}
double average_age = static_cast<double>(total_age) / students.size();
return {
static_cast<int>(students.size()),
average_age,
min_age,
max_age
};
}
void generateReport(const Statistics& stats, const std::string& filename) {
std::ofstream report(filename);
report << "Student Statistics Report\n";
report << "=========================\n";
report << "Total students: " << stats.total_students << "\n";
report << "Average age: " << stats.average_age << "\n";
report << "Age range: " << stats.min_age << " - " << stats.max_age << "\n";
}
public:
void processStudentData(const std::string& input_file, const std::string& output_file) {
students = loadStudentsFromFile(input_file);
Statistics stats = calculateStatistics(students);
generateReport(stats, output_file);
}
};
14.3.3 测试驱动开发(TDD) - 先写测试再写代码
TDD就像先尝味道再调味:
- 编写测试:先想好菜应该是什么味道
- 运行测试:确认现在的味道不对
- 编写代码:开始调味
- 运行测试:尝尝味道是否达标
- 重构:改善呈现方式
// 使用Google Test框架的TDD示例
#include <gtest/gtest.h>
// 第一步:编写测试(先定义期望的行为)
TEST(StudentRepositoryTest, AddStudentIncreasesCount) {
StudentRepository repo;
EXPECT_EQ(repo.getStudentCount(), 0); // 初始为空
repo.addStudent("John Doe");
EXPECT_EQ(repo.getStudentCount(), 1); // 添加后计数增加
repo.addStudent("Jane Smith");
EXPECT_EQ(repo.getStudentCount(), 2); // 继续增加
}
TEST(StudentRepositoryTest, GetStudentByIndex) {
StudentRepository repo;
repo.addStudent("John Doe");
repo.addStudent("Jane Smith");
EXPECT_EQ(repo.getStudentName(0), "John Doe");
EXPECT_EQ(repo.getStudentName(1), "Jane Smith");
}
TEST(StudentRepositoryTest, GetStudentWithInvalidIndex) {
StudentRepository repo;
repo.addStudent("John Doe");
EXPECT_THROW(repo.getStudentName(-1), std::out_of_range);
EXPECT_THROW(repo.getStudentName(1), std::out_of_range);
}
// 第二步:运行测试(确认失败)
// 第三步:编写最简单的代码让测试通过
class StudentRepository {
private:
std::vector<std::string> student_names;
public:
void addStudent(const std::string& name) {
student_names.push_back(name);
}
std::string getStudentName(int index) const {
if (index < 0 || index >= student_names.size()) {
throw std::out_of_range("Student index out of range");
}
return student_names[index];
}
int getStudentCount() const {
return student_names.size();
}
};
// 第四步:运行测试(确认通过)
// 第五步:重构(改善代码结构)
class StudentRepository {
private:
std::vector<Student> students;
public:
void addStudent(const Student& student) {
students.push_back(student);
}
Student getStudent(int index) const {
validateIndex(index);
return students[index];
}
int getStudentCount() const {
return students.size();
}
private:
void validateIndex(int index) const {
if (index < 0 || index >= students.size()) {
throw std::out_of_range("Student index " + std::to_string(index) +
" is out of range [0, " +
std::to_string(students.size()) + ")");
}
}
};
14.4 性能优化实战
14.4.1 性能分析 - 找到瓶颈所在
性能分析就像体检:
- CPU瓶颈:处理器使用率过高(就像心脏负担过重)
- 内存瓶颈:内存使用过多或内存泄漏(就像消化不良)
- I/O瓶颈:磁盘或网络I/O过慢(就像血液循环不畅)
// 简单的性能监控工具
class PerformanceMonitor {
private:
std::unordered_map<std::string, std::vector<double>> metrics;
public:
void recordMetric(const std::string& name, double value) {
metrics[name].push_back(value);
}
double getAverage(const std::string& name) const {
auto it = metrics.find(name);
if (it == metrics.end() || it->second.empty()) {
return 0.0;
}
double sum = std::accumulate(it->second.begin(), it->second.end(), 0.0);
return sum / it->second.size();
}
void printReport() const {
std::cout << "=== 性能报告 ===" << std::endl;
for (const auto& [name, values] : metrics) {
if (values.empty()) continue;
double avg = getAverage(name);
auto minmax = std::minmax_element(values.begin(), values.end());
std::cout << name << ":" << std::endl;
std::cout << " 平均: " << avg << " ms" << std::endl;
std::cout << " 最小: " << *minmax.first << " ms" << std::endl;
std::cout << " 最大: " << *minmax.second << " ms" << std::endl;
std::cout << " 调用次数: " << values.size() << std::endl;
std::cout << std::endl;
}
}
};
// 使用示例
class TimedOperation {
private:
std::string name;
std::chrono::high_resolution_clock::time_point start;
PerformanceMonitor& monitor;
public:
TimedOperation(const std::string& op_name, PerformanceMonitor& mon)
: name(op_name), monitor(mon) {
start = std::chrono::high_resolution_clock::now();
}
~TimedOperation() {
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration<double, std::milli>(end - start).count();
monitor.recordMetric(name, duration);
}
};
14.4.2 内存优化 - 高效使用内存
内存优化就像仓库管理:
- 内存池:预先分配,避免频繁申请释放(就像预先准备好常用食材)
- 对象池:重复使用对象(就像重复使用餐具)
- 智能指针:自动管理内存(就像自动洗碗机)
// 对象池模式:重用对象减少分配开销
template<typename T>
class ObjectPool {
private:
std::queue<std::unique_ptr<T>> available_objects;
std::vector<std::unique_ptr<T>> all_objects;
std::function<std::unique_ptr<T>()> creator;
public:
explicit ObjectPool(std::function<std::unique_ptr<T>()> create_func, size_t initial_size = 10)
: creator(create_func) {
for (size_t i = 0; i < initial_size; ++i) {
auto obj = creator();
all_objects.push_back(std::move(obj));
available_objects.push(std::make_unique<T>(*all_objects.back()));
}
}
std::unique_ptr<T> acquire() {
if (available_objects.empty()) {
auto obj = creator();
all_objects.push_back(std::move(obj));
return std::make_unique<T>(*all_objects.back());
}
auto obj = std::move(available_objects.front());
available_objects.pop();
return obj;
}
void release(std::unique_ptr<T> obj) {
// 重置对象状态(假设T有reset方法)
if (obj) {
obj->reset();
available_objects.push(std::move(obj));
}
}
size_t getAvailableCount() const {
return available_objects.size();
}
size_t getTotalCount() const {
return all_objects.size();
}
};
// 内存池:预分配大块内存
class MemoryPool {
private:
std::vector<char> pool;
size_t block_size;
size_t block_count;
std::vector<bool> block_usage;
std::queue<size_t> free_blocks;
public:
MemoryPool(size_t block_size, size_t initial_blocks)
: block_size(block_size), block_count(initial_blocks),
pool(block_size * initial_blocks), block_usage(initial_blocks, false) {
for (size_t i = 0; i < initial_blocks; ++i) {
free_blocks.push(i);
}
}
void* allocate() {
if (free_blocks.empty()) {
expandPool();
}
size_t block_index = free_blocks.front();
free_blocks.pop();
block_usage[block_index] = true;
return pool.data() + (block_index * block_size);
}
void deallocate(void* ptr) {
if (!ptr) return;
size_t offset = static_cast<char*>(ptr) - pool.data();
size_t block_index = offset / block_size;
if (block_index < block_count && block_usage[block_index]) {
block_usage[block_index] = false;
free_blocks.push(block_index);
}
}
private:
void expandPool() {
size_t old_count = block_count;
size_t new_count = old_count * 2;
pool.resize(block_size * new_count);
block_usage.resize(new_count, false);
for (size_t i = old_count; i < new_count; ++i) {
free_blocks.push(i);
}
block_count = new_count;
}
};
14.4.3 算法优化 - 选择合适的算法
算法优化就像选择最佳路线:
- 降低复杂度:从O(n²)优化到O(n log n)(就像从绕远路到走近路)
- 选择合适的数据结构:用哈希表代替线性搜索(就像用地图导航代替问路)
- 利用缓存:空间换时间(就像记住常用路线)
// 优化前:O(n²)复杂度
std::vector<int> findDuplicatesSlow(const std::vector<int>& data) {
std::vector<int> duplicates;
for (size_t i = 0; i < data.size(); ++i) {
for (size_t j = i + 1; j < data.size(); ++j) {
if (data[i] == data[j]) {
if (std::find(duplicates.begin(), duplicates.end(), data[i]) == duplicates.end()) {
duplicates.push_back(data[i]);
}
break;
}
}
}
return duplicates;
}
// 优化后:O(n)复杂度
std::vector<int> findDuplicatesFast(const std::vector<int>& data) {
std::unordered_set<int> seen;
std::unordered_set<int> duplicates;
for (int value : data) {
if (seen.count(value)) {
duplicates.insert(value);
} else {
seen.insert(value);
}
}
return std::vector<int>(duplicates.begin(), duplicates.end());
}
// 缓存优化:避免重复计算
class FibonacciCalculator {
private:
std::unordered_map<int, long long> cache{{0, 0}, {1, 1}};
public:
long long calculate(int n) {
if (n < 0) return 0;
auto it = cache.find(n);
if (it != cache.end()) {
return it->second;
}
long long result = calculate(n - 1) + calculate(n - 2);
cache[n] = result;
return result;
}
void clearCache() {
cache.clear();
cache[0] = 0;
cache[1] = 1;
}
size_t getCacheSize() const {
return cache.size();
}
};
// 并行优化:利用多核处理器
#include <thread>
#include <future>
#include <vector>
class ParallelProcessor {
public:
template<typename Func, typename InputIt, typename OutputIt>
static void parallelTransform(InputIt first, InputIt last, OutputIt result, Func func) {
const auto size = std::distance(first, last);
const auto num_threads = std::thread::hardware_concurrency();
const auto chunk_size = size / num_threads;
std::vector<std::future<void>> futures;
for (unsigned int i = 0; i < num_threads; ++i) {
auto start = std::next(first, i * chunk_size);
auto end = (i == num_threads - 1) ? last : std::next(start, chunk_size);
auto out = std::next(result, i * chunk_size);
futures.push_back(std::async(std::launch::async, [start, end, out, func]() {
std::transform(start, end, out, func);
}));
}
for (auto& future : futures) {
future.wait();
}
}
};
14.5 并发编程实战
14.5.1 并发基础 - 多线程编程
并发就像多窗口服务:
- 线程:每个服务窗口(轻量级,共享资源)
- 进程:每个独立的服务大厅(重量级,独立资源)
- 并发:多个窗口同时服务(不一定是同时,可能是交替)
- 并行:多个窗口真正同时服务(需要多核支持)
// 基本的线程使用
void workerFunction(int id, int duration) {
std::cout << "Worker " << id << " started, working for " << duration << "ms\n";
std::this_thread::sleep_for(std::chrono::milliseconds(duration));
std::cout << "Worker " << id << " finished\n";
}
class ThreadManager {
public:
static void demonstrateBasicThreads() {
std::cout << "=== 基本线程演示 ===\n";
// 创建多个工作线程
std::vector<std::thread> workers;
for (int i = 1; i <= 5; ++i) {
workers.emplace_back(workerFunction, i, i * 100);
}
std::cout << "All workers started, waiting for completion...\n";
// 等待所有线程完成
for (auto& worker : workers) {
worker.join();
}
std::cout << "All workers completed!\n";
}
static void demonstrateAsync() {
std::cout << "\n=== 异步任务演示 ===\n";
// 启动异步任务
auto future1 = std::async(std::launch::async, []() {
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
return 42;
});
auto future2 = std::async(std::launch::async, []() {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
return std::string("Hello from async task!");
});
std::cout << "Doing other work while async tasks run...\n";
// 获取异步结果(会阻塞直到结果可用)
int result1 = future1.get();
std::string result2 = future2.get();
std::cout << "Async results: " << result1 << ", " << result2 << "\n";
}
};
14.5.2 线程同步 - 避免竞态条件
线程同步就像交通信号灯:
- 互斥锁:一次只允许一辆车通过(最严格的控制)
- 读写锁:读操作可以同时进行,写操作需要独占
- 条件变量:等待某个条件满足再继续执行
// 线程安全的计数器
class ThreadSafeCounter {
private:
int count;
mutable std::mutex mtx; // mutable允许const方法中修改
public:
ThreadSafeCounter() : count(0) {}
void increment() {
std::lock_guard<std::mutex> lock(mtx);
++count;
}
void decrement() {
std::lock_guard<std::mutex> lock(mtx);
--count;
}
int getCount() const {
std::lock_guard<std::mutex> lock(mtx);
return count;
}
void reset() {
std::lock_guard<std::mutex> lock(mtx);
count = 0;
}
};
// 读写锁示例:允许多个读者,但写者需要独占
class ThreadSafeDataCache {
private:
mutable std::shared_mutex rw_mutex;
std::unordered_map<std::string, std::string> cache;
public:
// 读操作:多个线程可以同时读取
std::optional<std::string> get(const std::string& key) const {
std::shared_lock<std::shared_mutex> lock(rw_mutex);
auto it = cache.find(key);
if (it != cache.end()) {
return it->second;
}
return std::nullopt;
}
// 写操作:需要独占访问
void set(const std::string& key, const std::string& value) {
std::unique_lock<std::shared_mutex> lock(rw_mutex);
cache[key] = value;
}
// 删除操作:也需要独占访问
bool remove(const std::string& key) {
std::unique_lock<std::shared_mutex> lock(rw_mutex);
return cache.erase(key) > 0;
}
size_t size() const {
std::shared_lock<std::shared_mutex> lock(rw_mutex);
return cache.size();
}
};
// 条件变量示例:线程间的信号通知
class ThreadSafeQueue {
private:
mutable std::mutex mtx;
std::condition_variable cv;
std::queue<int> queue;
bool shutdown = false;
public:
void push(int value) {
{
std::lock_guard<std::mutex> lock(mtx);
queue.push(value);
}
cv.notify_one(); // 通知一个等待的线程
}
std::optional<int> pop() {
std::unique_lock<std::mutex> lock(mtx);
// 等待队列非空或关闭信号
cv.wait(lock, [this] { return !queue.empty() || shutdown; });
if (shutdown && queue.empty()) {
return std::nullopt; // 关闭信号且队列为空
}
int value = queue.front();
queue.pop();
return value;
}
void shutdownQueue() {
{
std::lock_guard<std::mutex> lock(mtx);
shutdown = true;
}
cv.notify_all(); // 通知所有等待的线程
}
bool isShutdown() const {
std::lock_guard<std::mutex> lock(mtx);
return shutdown;
}
};
14.5.3 并发设计模式
生产者-消费者模式:就像餐厅厨房和服务员
- 生产者:厨师做菜
- 消费者:服务员上菜
- 缓冲区:出菜口暂存做好的菜
// 生产者-消费者模式实现
class ProducerConsumerSystem {
private:
ThreadSafeQueue queue;
std::atomic<bool> running{true};
std::vector<std::thread> producers;
std::vector<std::thread> consumers;
void producerTask(int id) {
int item = 0;
while (running) {
int value = id * 1000 + item++;
queue.push(value);
std::cout << "Producer " << id << " produced: " << value << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
void consumerTask(int id) {
while (running) {
auto result = queue.pop();
if (result.has_value()) {
std::cout << "Consumer " << id << " consumed: " << result.value() << std::endl;
}
std::this_thread::sleep_for(std::chrono::milliseconds(150));
}
}
public:
void start(int num_producers, int num_consumers) {
// 启动生产者线程
for (int i = 0; i < num_producers; ++i) {
producers.emplace_back(&ProducerConsumerSystem::producerTask, this, i);
}
// 启动消费者线程
for (int i = 0; i < num_consumers; ++i) {
consumers.emplace_back(&ProducerConsumerSystem::consumerTask, this, i);
}
}
void stop() {
running = false;
queue.shutdownQueue();
// 等待所有线程完成
for (auto& producer : producers) {
if (producer.joinable()) {
producer.join();
}
}
for (auto& consumer : consumers) {
if (consumer.joinable()) {
consumer.join();
}
}
}
~ProducerConsumerSystem() {
if (running) {
stop();
}
}
};
14.6 综合项目实战
14.6.1 完整的学生管理系统
由于篇幅限制,这里展示核心架构:
// 核心架构展示
class StudentManagementSystem {
private:
std::shared_ptr<StudentRepository> repository;
std::unique_ptr<StudentService> service;
std::unique_ptr<StudentManagementUI> ui;
public:
StudentManagementSystem(const std::string& storage_type, const std::string& config_file) {
// 根据配置创建不同类型的仓库
if (storage_type == "memory") {
repository = std::make_shared<InMemoryStudentRepository>();
} else if (storage_type == "file") {
repository = std::make_shared<FileStudentRepository>(config_file);
}
service = std::make_unique<StudentService>(repository);
ui = std::make_unique<StudentManagementUI>(*service);
}
void run() {
ui->run();
}
};
int main() {
try {
StudentManagementSystem system("file", "students.csv");
system.run();
} catch (const std::exception& e) {
std::cerr << "系统启动失败: " << e.what() << std::endl;
return 1;
}
return 0;
}
14.6.2 性能监控集成
// 集成性能监控的服务装饰器
class MonitoredStudentService : public StudentService {
private:
StudentService& base_service;
PerformanceMonitor& monitor;
public:
MonitoredStudentService(StudentService& service, PerformanceMonitor& mon)
: base_service(service), monitor(mon) {}
void addStudent(const Student& student) override {
TimedOperation op("addStudent", monitor);
base_service.addStudent(student);
}
Student getStudent(const std::string& id) override {
TimedOperation op("getStudent", monitor);
return base_service.getStudent(id);
}
std::vector<Student> getAllStudents() override {
TimedOperation op("getAllStudents", monitor);
return base_service.getAllStudents();
}
void printPerformanceReport() {
monitor.printReport();
}
};
14.6.3 并发处理集成
// 支持并发操作的服务
class ConcurrentStudentService {
private:
std::shared_ptr<StudentRepository> repository;
mutable std::shared_mutex rw_mutex;
public:
explicit ConcurrentStudentService(std::shared_ptr<StudentRepository> repo)
: repository(std::move(repo)) {}
// 读操作:使用共享锁
std::vector<Student> getAllStudents() const {
std::shared_lock<std::shared_mutex> lock(rw_mutex);
return repository->findAll();
}
std::optional<Student> getStudent(const std::string& id) const {
std::shared_lock<std::shared_mutex> lock(rw_mutex);
return repository->findById(id);
}
// 写操作:使用独占锁
void addStudent(const Student& student) {
std::unique_lock<std::shared_mutex> lock(rw_mutex);
repository->save(student);
}
void updateStudent(const Student& student) {
std::unique_lock<std::shared_mutex> lock(rw_mutex);
repository->save(student);
}
void removeStudent(const std::string& id) {
std::unique_lock<std::shared_mutex> lock(rw_mutex);
repository->remove(id);
}
};
14.7 项目部署与维护
14.7.1 构建系统设计
CMake配置示例:
cmake_minimum_required(VERSION 3.10)
project(StudentManagementSystem VERSION 1.0.0)
# 设置C++标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 添加编译选项
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
add_compile_options(-Wall -Wextra -Wpedantic -Werror)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
add_compile_options(/W4 /WX)
endif()
# 添加测试选项
option(BUILD_TESTS "Build tests" ON)
option(BUILD_DOCS "Build documentation" ON)
# 源文件
set(SOURCES
src/student.cpp
src/repository.cpp
src/service.cpp
src/main.cpp
)
# 头文件
set(HEADERS
include/student.h
include/repository.h
include/service.h
)
# 创建可执行文件
add_executable(student_management ${SOURCES} ${HEADERS})
# 设置包含目录
target_include_directories(student_management PRIVATE include)
# 测试
if(BUILD_TESTS)
enable_testing()
add_subdirectory(tests)
endif()
14.7.2 测试策略
单元测试示例:
#include <gtest/gtest.h>
#include "student.h"
#include "student_service.h"
class StudentServiceTest : public ::testing::Test {
protected:
void SetUp() override {
auto repo = std::make_shared<InMemoryStudentRepository>();
service_ = std::make_unique<StudentService>(repo);
}
std::unique_ptr<StudentService> service_;
};
TEST_F(StudentServiceTest, AddValidStudent) {
Student student("S001", "John Doe", 20);
EXPECT_NO_THROW(service_->addStudent(student));
auto found = service_->findStudent("S001");
EXPECT_TRUE(found.has_value());
EXPECT_EQ(found->getName(), "John Doe");
}
TEST_F(StudentServiceTest, AddInvalidStudent) {
Student student("", "", -1); // 无效数据
EXPECT_THROW(service_->addStudent(student), std::invalid_argument);
}
14.7.3 持续集成与部署
CI/CD流程:
- 代码提交:开发者提交代码到版本控制
- 自动构建:CI系统自动编译代码
- 自动测试:运行单元测试和集成测试
- 代码质量检查:静态代码分析
- 自动部署:通过测试的代码自动部署到测试环境
- 性能监控:监控应用性能和错误率
14.8 学习要点总结
14.8.1 核心概念回顾
- SOLID原则:掌握面向对象设计的五大原则
- 设计模式:理解常用设计模式的应用场景
- 项目管理:学会需求分析、风险管理和开发流程
- 代码质量:重视代码可读性、可维护性和测试
- 性能优化:掌握性能分析和优化技巧
- 并发编程:理解多线程编程和同步机制
14.8.2 最佳实践
- 先设计后编码:不要急于写代码,先思考架构
- 小步快跑:采用迭代开发,快速验证想法
- 测试驱动:先写测试,再写实现
- 持续重构:定期改善代码结构
- 监控性能:持续监控应用性能
- 团队协作:重视代码审查和知识分享
14.8.3 常见陷阱
- 过度设计:不要为了使用设计模式而使用设计模式
- 忽视测试:测试不是可有可无的,是必须的
- 性能过早优化:先让代码正确,再让代码快速
- 忽略错误处理:异常处理要周全
- 代码重复:发现重复代码就要考虑提取
- 文档缺失:好的代码需要好的文档
通过掌握这些综合项目开发技能,你将能够开发出高质量、可维护、高性能的C++应用程序。记住:好的软件不是写出来的,是设计出来的!
更多推荐



所有评论(0)