第13章 类与封装

面向对象设计概述

面向对象设计(Object-Oriented Design,OOD)是一种基于对象概念的软件开发方法,它通过抽象、封装、继承和多态等核心机制,将系统分解为相互协作的对象集合,每个对象封装了特定的职责和行为。

面向对象设计的核心原则

  1. 抽象(Abstraction):从具体实现中提取本质特征,形成抽象接口,隐藏实现细节
  2. 封装(Encapsulation):将数据和操作数据的方法绑定在一起,通过访问控制实现信息隐藏
  3. 继承(Inheritance):通过层次结构实现代码重用和类型扩展,建立”is-a”关系
  4. 多态(Polymorphism):通过统一接口支持不同实现,提高代码的灵活性和可扩展性
  5. 组合(Composition):通过对象组合实现更灵活的代码重用,建立”has-a”关系

面向对象设计的价值

  • 可维护性:模块化设计和信息隐藏使得代码更易于理解和修改
  • 可扩展性:通过继承和多态,系统可以在不修改现有代码的情况下进行扩展
  • 可重用性:封装和抽象使得组件可以在不同场景中重复使用
  • 可测试性:模块化设计使得单元测试更加容易实现
  • 代码清晰度:面向对象的设计更符合人类的思维模式,提高代码的可读性

类设计与封装原则

SOLID设计原则深度解析

SOLID是由Robert C. Martin提出的一组面向对象设计基本原则,它们为创建高质量、可维护的软件系统提供了坚实的理论基础。

单一职责原则(Single Responsibility Principle - SRP)

核心思想:一个类应该只有一个职责,只有一个引起它变化的原因。

技术实现

  • 将不同职责分离到不同的类中
  • 每个类专注于解决一个特定问题
  • 职责边界清晰,便于理解和维护

实际应用场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// 违反单一职责原则的示例
class User {
public:
// 数据访问职责
void saveToDatabase() { /* 保存用户到数据库 */ }
User loadFromDatabase(int id) { /* 从数据库加载用户 */ }

// 业务逻辑职责
bool validate() { /* 验证用户数据 */ }

// 通信职责
void sendVerificationEmail() { /* 发送验证邮件 */ }
};

// 遵循单一职责原则的示例
class User {
public:
// 仅包含数据和基本行为
std::string getName() const { return name; }
void setName(const std::string& name) { this->name = name; }
// 其他属性和基本方法
private:
std::string name;
std::string email;
// 其他属性
};

class UserRepository {
public:
// 数据访问职责
void save(const User& user) {
// 实现数据库保存逻辑
std::cout << "Saving user " << user.getName() << " to database" << std::endl;
}

User findById(int id) {
// 实现数据库查询逻辑
std::cout << "Finding user with id " << id << " from database" << std::endl;
return User(); // 简化示例
}
};

class UserValidator {
public:
// 验证职责
bool isValid(const User& user) {
return !user.getName().empty() && !user.getEmail().empty();
}
};

class EmailService {
public:
// 通信职责
void sendVerificationEmail(const User& user) {
std::cout << "Sending verification email to " << user.getEmail() << std::endl;
}
};

优势

  • 提高代码的可维护性和可测试性
  • 减少类之间的耦合
  • 便于团队协作和代码复用
  • 降低修改代码时引入错误的风险

开放封闭原则(Open-Closed Principle - OCP)

核心思想:软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。

技术实现

  • 通过抽象基类定义接口
  • 使用继承和多态实现扩展
  • 依赖抽象而非具体实现
  • 利用设计模式(如策略模式、工厂模式)支持扩展

实际应用场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// 违反开放封闭原则的示例
class Shape {
public:
enum Type { CIRCLE, RECTANGLE, TRIANGLE };
Type type;

// 不同形状的属性
double radius; // 圆形半径
double width; // 矩形宽度
double height; // 矩形高度/三角形高度
double base; // 三角形底边
};

class AreaCalculator {
public:
double calculateArea(const Shape& shape) {
switch (shape.type) {
case Shape::CIRCLE:
return M_PI * shape.radius * shape.radius;
case Shape::RECTANGLE:
return shape.width * shape.height;
case Shape::TRIANGLE:
return 0.5 * shape.base * shape.height;
default:
return 0;
}
}

// 问题:添加新形状时需要修改此方法
};

// 遵循开放封闭原则的示例
class Shape {
public:
virtual ~Shape() = default;
virtual double calculateArea() const = 0;
virtual std::string getName() const = 0;
};

class Circle : public Shape {
public:
explicit Circle(double radius) : radius(radius) {}

double calculateArea() const override {
return M_PI * radius * radius;
}

std::string getName() const override {
return "Circle";
}

double getRadius() const {
return radius;
}

private:
double radius;
};

class Rectangle : public Shape {
public:
Rectangle(double width, double height) : width(width), height(height) {}

double calculateArea() const override {
return width * height;
}

std::string getName() const override {
return "Rectangle";
}

double getWidth() const { return width; }
double getHeight() const { return height; }

private:
double width, height;
};

class Triangle : public Shape {
public:
Triangle(double base, double height) : base(base), height(height) {}

double calculateArea() const override {
return 0.5 * base * height;
}

std::string getName() const override {
return "Triangle";
}

private:
double base, height;
};

class AreaCalculator {
public:
double calculateArea(const Shape& shape) {
return shape.calculateArea();
}

void printArea(const Shape& shape) {
std::cout << "Area of " << shape.getName() << ": " << calculateArea(shape) << std::endl;
}

// 优势:添加新形状时无需修改此类
};

// 扩展示例:添加新的形状
class Square : public Shape {
public:
explicit Square(double side) : side(side) {}

double calculateArea() const override {
return side * side;
}

std::string getName() const override {
return "Square";
}

private:
double side;
};

优势

  • 提高代码的可扩展性和可维护性
  • 减少修改现有代码时引入错误的风险
  • 支持增量开发和团队协作
  • 符合软件设计的”开闭”哲学

实现技巧

  • 使用抽象基类定义稳定的接口
  • 利用多态实现行为的动态绑定
  • 应用依赖倒置原则,依赖抽象而非具体实现
  • 结合工厂模式创建对象,隐藏具体实现细节

里氏替换原则(Liskov Substitution Principle - LSP)

核心思想:子类应该可以替换其父类,而不会影响程序的正确性。也就是说,使用基类指针或引用的代码,在替换为派生类对象时,程序的行为应该保持不变。

技术实现

  • 子类必须完全遵守基类的接口约定
  • 子类不能强化前置条件(preconditions)
  • 子类不能弱化后置条件(postconditions)
  • 子类必须保持基类的不变量(invariants)
  • 子类方法的异常类型不能比基类更宽

实际应用场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// 违反里氏替换原则的示例
class Rectangle {
protected:
double width;
double height;

public:
Rectangle(double w, double h) : width(w), height(h) {}

virtual void setWidth(double w) {
width = w;
}

virtual void setHeight(double h) {
height = h;
}

double getWidth() const { return width; }
double getHeight() const { return height; }

double calculateArea() const {
return width * height;
}
};

class Square : public Rectangle {
public:
explicit Square(double side) : Rectangle(side, side) {}

// 违反LSP:改变了基类的行为约定
void setWidth(double w) override {
width = w;
height = w; // 同时修改height
}

void setHeight(double h) override {
height = h;
width = h; // 同时修改width
}
};

// 问题:基类用户期望setWidth只修改宽度,setHeight只修改高度
void processRectangle(Rectangle& rect) {
double originalWidth = rect.getWidth();
rect.setHeight(10);
// 期望:宽度保持不变
assert(rect.getWidth() == originalWidth);
// 对于Square:断言失败!
}

// 遵循里氏替换原则的示例
class Shape {
public:
virtual ~Shape() = default;
virtual double calculateArea() const = 0;
virtual std::string getName() const = 0;
};

class Rectangle : public Shape {
private:
double width;
double height;

public:
Rectangle(double w, double h) : width(w), height(h) {}

void setWidth(double w) {
width = w;
}

void setHeight(double h) {
height = h;
}

double getWidth() const { return width; }
double getHeight() const { return height; }

double calculateArea() const override {
return width * height;
}

std::string getName() const override {
return "Rectangle";
}
};

class Square : public Shape {
private:
double side;

public:
explicit Square(double side) : side(side) {}

void setSide(double s) {
side = s;
}

double getSide() const { return side; }

double calculateArea() const override {
return side * side;
}

std::string getName() const override {
return "Square";
}
};

// 正确使用:通过Shape接口
void processShape(Shape& shape) {
std::cout << "Area of " << shape.getName() << ": " << shape.calculateArea() << std::endl;
}

// 动物示例(修正版)
class Bird {
public:
virtual ~Bird() = default;
virtual void makeSound() = 0;
virtual void eat() = 0;
};

class FlyingBird : public Bird {
public:
virtual void fly() = 0;
};

class Sparrow : public FlyingBird {
public:
void makeSound() override {
std::cout << "Sparrow: Chirp chirp!" << std::endl;
}

void eat() override {
std::cout << "Sparrow: Eating seeds" << std::endl;
}

void fly() override {
std::cout << "Sparrow: Flying high" << std::endl;
}
};

class Penguin : public Bird {
public:
void makeSound() override {
std::cout << "Penguin: Honk honk!" << std::endl;
}

void eat() override {
std::cout << "Penguin: Eating fish" << std::endl;
}

// 企鹅不会飞,所以没有fly方法
void swim() {
std::cout << "Penguin: Swimming in the ocean" << std::endl;
}
};

优势

  • 确保继承层次的正确性和一致性
  • 提高代码的可维护性和可预测性
  • 支持多态的正确使用
  • 减少运行时错误的可能性

常见违反LSP的情况

  • 子类抛出基类不抛出的异常
  • 子类改变基类方法的返回值语义
  • 子类违反基类的方法约定
  • 子类修改基类的私有状态(通过不安全的强制转换)

接口隔离原则(Interface Segregation Principle - ISP)

核心思想:客户端不应该依赖它不使用的接口。一个类对另一个类的依赖应该建立在最小的接口上。

技术实现

  • 将大接口拆分为多个小接口
  • 每个接口专注于特定的功能组
  • 客户端只实现它们需要的接口
  • 避免”胖接口”(fat interfaces)
  • 使用接口组合而非单一继承

实际应用场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
// 违反接口隔离原则的示例
class Employee {
public:
virtual void work() = 0;
virtual void takeBreak() = 0;
virtual void attendMeeting() = 0;
virtual void submitReport() = 0;
virtual void manageTeam() = 0; // 只有管理层需要
};

class Developer : public Employee {
public:
void work() override { /* 编写代码 */ }
void takeBreak() override { /* 休息 */ }
void attendMeeting() override { /* 参加会议 */ }
void submitReport() override { /* 提交报告 */ }
void manageTeam() override {
// 开发者不需要管理团队,空实现或抛出异常
throw std::runtime_error("Developers don't manage teams");
}
};

class Manager : public Employee {
public:
void work() override { /* 管理工作 */ }
void takeBreak() override { /* 休息 */ }
void attendMeeting() override { /* 参加会议 */ }
void submitReport() override { /* 提交报告 */ }
void manageTeam() override { /* 管理团队 */ }
};

// 遵循接口隔离原则的示例
class Workable {
public:
virtual ~Workable() = default;
virtual void work() = 0;
};

class Breakable {
public:
virtual ~Breakable() = default;
virtual void takeBreak() = 0;
};

class MeetingAttendable {
public:
virtual ~MeetingAttendable() = default;
virtual void attendMeeting() = 0;
};

class Reportable {
public:
virtual ~Reportable() = default;
virtual void submitReport() = 0;
};

class TeamManageable {
public:
virtual ~TeamManageable() = default;
virtual void manageTeam() = 0;
};

// 开发者只实现需要的接口
class Developer : public Workable, public Breakable, public MeetingAttendable, public Reportable {
public:
void work() override {
std::cout << "Developer: Writing code" << std::endl;
}

void takeBreak() override {
std::cout << "Developer: Taking a break" << std::endl;
}

void attendMeeting() override {
std::cout << "Developer: Attending a meeting" << std::endl;
}

void submitReport() override {
std::cout << "Developer: Submitting a report" << std::endl;
}
};

// 管理者实现所有接口,包括团队管理
class Manager : public Workable, public Breakable, public MeetingAttendable, public Reportable, public TeamManageable {
public:
void work() override {
std::cout << "Manager: Managing work" << std::endl;
}

void takeBreak() override {
std::cout << "Manager: Taking a break" << std::endl;
}

void attendMeeting() override {
std::cout << "Manager: Attending a meeting" << std::endl;
}

void submitReport() override {
std::cout << "Manager: Submitting a report" << std::endl;
}

void manageTeam() override {
std::cout << "Manager: Managing the team" << std::endl;
}
};

// 机器人只实现工作接口
class Robot : public Workable {
public:
void work() override {
std::cout << "Robot: Performing tasks" << std::endl;
}
};

优势

  • 减少接口污染,提高接口的内聚性
  • 避免不必要的方法实现
  • 降低类之间的耦合度
  • 提高代码的可维护性和可测试性
  • 支持更灵活的组合方式

现代C++中的接口隔离

  • 使用纯抽象类定义接口
  • 利用C++20的概念(Concepts)进一步约束接口
  • 使用lambda表达式和函数对象实现更灵活的行为注入
  • 结合依赖注入框架实现松耦合设计

依赖倒置原则(Dependency Inversion Principle - DIP)

核心思想:高层模块不应该依赖低层模块,两者都应该依赖抽象。抽象不应该依赖细节,细节应该依赖抽象。

技术实现

  • 定义抽象接口作为模块间的契约
  • 使用依赖注入(构造函数注入、 setter 注入、接口注入)
  • 避免硬编码依赖关系
  • 使用工厂模式或依赖注入容器管理依赖
  • 采用控制反转(IoC)思想

实际应用场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// 违反依赖倒置原则的示例
class MySQLDatabase {
public:
void connect() { /* 连接MySQL数据库 */ }
void executeQuery(const std::string& query) { /* 执行SQL查询 */ }
};

class UserService {
public:
UserService() : db(MySQLDatabase()) {}

void createUser(const std::string& name, const std::string& email) {
db.connect();
std::string query = "INSERT INTO users (name, email) VALUES ('" + name + "', '" + email + "')";
db.executeQuery(query);
}

private:
MySQLDatabase db; // 直接依赖具体实现
};

// 问题:UserService强依赖于MySQLDatabase,如果需要切换到其他数据库,需要修改UserService代码

// 遵循依赖倒置原则的示例
class Database {
public:
virtual ~Database() = default;
virtual void connect() = 0;
virtual void executeQuery(const std::string& query) = 0;
};

class MySQLDatabase : public Database {
public:
void connect() override {
std::cout << "Connecting to MySQL database" << std::endl;
}

void executeQuery(const std::string& query) override {
std::cout << "Executing MySQL query: " << query << std::endl;
}
};

class PostgreSQLDatabase : public Database {
public:
void connect() override {
std::cout << "Connecting to PostgreSQL database" << std::endl;
}

void executeQuery(const std::string& query) override {
std::cout << "Executing PostgreSQL query: " << query << std::endl;
}
};

class UserService {
public:
// 构造函数注入
explicit UserService(std::unique_ptr<Database> db) : db(std::move(db)) {}

void createUser(const std::string& name, const std::string& email) {
db->connect();
std::string query = "INSERT INTO users (name, email) VALUES ('" + name + "', '" + email + "')";
db->executeQuery(query);
}

private:
std::unique_ptr<Database> db; // 依赖抽象接口
};

// 使用示例
int main() {
// 可以轻松切换数据库实现
auto mysqlDb = std::make_unique<MySQLDatabase>();
UserService userServiceWithMySQL(std::move(mysqlDb));
userServiceWithMySQL.createUser("Alice", "alice@example.com");

auto postgresDb = std::make_unique<PostgreSQLDatabase>();
UserService userServiceWithPostgres(std::move(postgresDb));
userServiceWithPostgres.createUser("Bob", "bob@example.com");

return 0;
}

// 更复杂的示例:依赖注入容器
class DependencyContainer {
public:
template <typename T, typename... Args>
void registerType(Args&&... args) {
// 注册类型到容器
}

template <typename T>
std::unique_ptr<T> resolve() {
// 从容器解析依赖
return nullptr; // 简化示例
}
};

优势

  • 提高代码的可测试性(便于使用模拟对象)
  • 增强系统的可扩展性(易于添加新的实现)
  • 降低模块间的耦合度
  • 提高代码的可维护性和可读性
  • 支持并行开发(团队可以独立开发不同模块)

依赖注入的实现方式

  1. 构造函数注入:通过构造函数传递依赖(最常用,推荐)
  2. Setter注入:通过setter方法设置依赖
  3. 接口注入:通过实现特定接口来注入依赖
  4. 依赖注入容器:使用专门的容器管理依赖关系

与其他原则的关系

  • DIP是实现OCP的关键(通过抽象支持扩展)
  • DIP支持ISP(通过抽象接口隔离)
  • DIP有助于实现SRP(通过依赖管理简化职责)

高级设计模式与实践

设计模式是在软件设计中反复出现的问题的可重用解决方案,它们是经过验证的最佳实践,可以帮助开发者更有效地解决常见的设计问题。

创建型设计模式深度解析

创建型模式专注于对象的创建过程,提供了灵活的对象创建机制,隐藏了创建细节,提高了代码的可维护性和可扩展性。

单例模式(Singleton)

核心思想:确保一个类只有一个实例,并提供一个全局访问点。

技术实现

  • 私有构造函数防止外部实例化
  • 静态方法提供全局访问点
  • 禁止拷贝和移动操作
  • 线程安全的实现(C++11后使用局部静态变量)
  • 懒加载或饿加载策略

实际应用场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// 线程安全的单例模式实现(C++11及以上)
class Singleton {
public:
// 全局访问点
static Singleton& getInstance() {
// C++11保证局部静态变量的初始化是线程安全的
static Singleton instance;
return instance;
}

// 禁止拷贝和移动
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
Singleton(Singleton&&) = delete;
Singleton& operator=(Singleton&&) = delete;

// 业务方法
void initialize(const std::string& config) {
if (!initialized) {
this->config = config;
initialized = true;
std::cout << "Singleton initialized with config: " << config << std::endl;
}
}

void doSomething() {
if (!initialized) {
throw std::runtime_error("Singleton not initialized");
}
std::cout << "Singleton doing something with config: " << config << std::endl;
}

bool isInitialized() const {
return initialized;
}

private:
// 私有构造函数
Singleton() : initialized(false) {
std::cout << "Singleton instance created" << std::endl;
}

// 成员变量
bool initialized;
std::string config;
};

// 单例模式的应用场景:配置管理器
class ConfigManager : public Singleton {
public:
static ConfigManager& getInstance() {
static ConfigManager instance;
return instance;
}

void loadConfig(const std::string& filePath) {
// 加载配置文件
std::cout << "Loading config from " << filePath << std::endl;
// 模拟加载配置
configs["database"] = "localhost:3306";
configs["api_key"] = "secret_key_123";
}

std::string getConfig(const std::string& key) {
auto it = configs.find(key);
if (it != configs.end()) {
return it->second;
}
return "";
}

private:
ConfigManager() = default;
std::unordered_map<std::string, std::string> configs;
};

// 使用示例
void useSingletonPattern() {
// 获取单例实例
auto& singleton = Singleton::getInstance();

// 初始化
singleton.initialize("production");

// 使用
singleton.doSomething();

// 验证只有一个实例
auto& anotherReference = Singleton::getInstance();
std::cout << "Same instance: " << (&singleton == &anotherReference) << std::endl;

// 使用配置管理器
auto& configManager = ConfigManager::getInstance();
configManager.loadConfig("config.json");
std::cout << "Database config: " << configManager.getConfig("database") << std::endl;
}

优点

  • 确保唯一实例,避免资源浪费
  • 提供全局访问点,方便使用
  • 懒加载,按需创建实例
  • 线程安全(C++11后)

缺点

  • 违反单一职责原则
  • 增加代码耦合度
  • 测试困难(难以模拟)
  • 可能导致内存泄漏(如果实例持有资源)

适用场景

  • 配置管理器
  • 日志系统
  • 数据库连接池
  • 线程池
  • 全局缓存

工厂方法模式(Factory Method)

核心思想:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

技术实现

  • 抽象产品类定义产品接口
  • 具体产品类实现产品接口
  • 抽象创建者类定义工厂方法
  • 具体创建者类实现工厂方法,创建具体产品
  • 使用依赖倒置原则,依赖抽象而非具体实现

实际应用场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// 产品接口
class Logger {
public:
virtual ~Logger() = default;
virtual void log(const std::string& message) = 0;
virtual void logError(const std::string& message) = 0;
virtual void logWarning(const std::string& message) = 0;
};

// 具体产品:控制台日志
class ConsoleLogger : public Logger {
public:
void log(const std::string& message) override {
std::cout << "[INFO] " << message << std::endl;
}

void logError(const std::string& message) override {
std::cerr << "[ERROR] " << message << std::endl;
}

void logWarning(const std::string& message) override {
std::cout << "[WARNING] " << message << std::endl;
}
};

// 具体产品:文件日志
class FileLogger : public Logger {
private:
std::ofstream file;

public:
explicit FileLogger(const std::string& filename) {
file.open(filename, std::ios::app);
if (!file.is_open()) {
throw std::runtime_error("Failed to open log file");
}
}

~FileLogger() {
if (file.is_open()) {
file.close();
}
}

void log(const std::string& message) override {
if (file.is_open()) {
file << "[INFO] " << getCurrentTime() << " " << message << std::endl;
}
}

void logError(const std::string& message) override {
if (file.is_open()) {
file << "[ERROR] " << getCurrentTime() << " " << message << std::endl;
}
}

void logWarning(const std::string& message) override {
if (file.is_open()) {
file << "[WARNING] " << getCurrentTime() << " " << message << std::endl;
}
}

private:
std::string getCurrentTime() {
auto now = std::chrono::system_clock::now();
auto time = std::chrono::system_clock::to_time_t(now);
std::stringstream ss;
ss << std::put_time(std::localtime(&time), "%Y-%m-%d %H:%M:%S");
return ss.str();
}
};

// 抽象创建者
class LoggerFactory {
public:
virtual ~LoggerFactory() = default;
virtual std::unique_ptr<Logger> createLogger() = 0;

// 工厂方法的客户端代码
void logMessage(const std::string& message) {
auto logger = createLogger();
logger->log(message);
}
};

// 具体创建者:控制台日志工厂
class ConsoleLoggerFactory : public LoggerFactory {
public:
std::unique_ptr<Logger> createLogger() override {
return std::make_unique<ConsoleLogger>();
}
};

// 具体创建者:文件日志工厂
class FileLoggerFactory : public LoggerFactory {
private:
std::string filename;

public:
explicit FileLoggerFactory(std::string filename) : filename(std::move(filename)) {}

std::unique_ptr<Logger> createLogger() override {
return std::make_unique<FileLogger>(filename);
}
};

// 使用示例
void useFactoryMethodPattern() {
// 使用控制台日志工厂
ConsoleLoggerFactory consoleFactory;
consoleFactory.logMessage("Application started");

// 使用文件日志工厂
FileLoggerFactory fileFactory("app.log");
fileFactory.logMessage("Application started");

// 直接使用工厂创建日志器
auto consoleLogger = consoleFactory.createLogger();
consoleLogger->logError("An error occurred");

auto fileLogger = fileFactory.createLogger();
fileLogger->logWarning("A warning message");
}

优点

  • 遵循开放封闭原则,添加新产品时无需修改现有代码
  • 遵循单一职责原则,每个工厂只负责创建一种产品
  • 隐藏产品创建细节,客户端只关心产品接口
  • 提高代码的可测试性,便于模拟产品

缺点

  • 增加了类的数量,系统变得更复杂
  • 对于简单的对象创建,可能过于繁琐

适用场景

  • 产品类型不确定,需要在运行时动态创建
  • 产品创建过程复杂,需要封装创建逻辑
  • 系统需要遵循开放封闭原则,支持产品扩展
  • 客户端不关心产品的具体实现,只使用产品接口

抽象工厂模式(Abstract Factory)

核心思想:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。抽象工厂模式是工厂方法模式的扩展,用于创建产品族。

技术实现

  • 抽象产品类定义产品接口
  • 具体产品类实现产品接口
  • 抽象工厂类定义创建产品族的接口
  • 具体工厂类实现创建产品族的方法
  • 产品族中的产品相互配合使用

实际应用场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// 产品接口:按钮
class Button {
public:
virtual ~Button() = default;
virtual void render() = 0;
virtual void onClick() = 0;
};

// 具体产品:Windows按钮
class WindowsButton : public Button {
public:
void render() override {
std::cout << "Rendering Windows button" << std::endl;
}

void onClick() override {
std::cout << "Windows button clicked" << std::endl;
}
};

// 具体产品:macOS按钮
class MacOSButton : public Button {
public:
void render() override {
std::cout << "Rendering macOS button" << std::endl;
}

void onClick() override {
std::cout << "macOS button clicked" << std::endl;
}
};

// 产品接口:文本框
class TextBox {
public:
virtual ~TextBox() = default;
virtual void render() = 0;
virtual void setText(const std::string& text) = 0;
virtual std::string getText() = 0;
};

// 具体产品:Windows文本框
class WindowsTextBox : public TextBox {
private:
std::string text;

public:
void render() override {
std::cout << "Rendering Windows text box with text: '" << text << "'" << std::endl;
}

void setText(const std::string& text) override {
this->text = text;
}

std::string getText() override {
return text;
}
};

// 具体产品:macOS文本框
class MacOSTextBox : public TextBox {
private:
std::string text;

public:
void render() override {
std::cout << "Rendering macOS text box with text: '" << text << "'" << std::endl;
}

void setText(const std::string& text) override {
this->text = text;
}

std::string getText() override {
return text;
}
};

// 抽象工厂:UI组件工厂
class UIFactory {
public:
virtual ~UIFactory() = default;
virtual std::unique_ptr<Button> createButton() = 0;
virtual std::unique_ptr<TextBox> createTextBox() = 0;
};

// 具体工厂:Windows UI工厂
class WindowsUIFactory : public UIFactory {
public:
std::unique_ptr<Button> createButton() override {
return std::make_unique<WindowsButton>();
}

std::unique_ptr<TextBox> createTextBox() override {
return std::make_unique<WindowsTextBox>();
}
};

// 具体工厂:macOS UI工厂
class MacOSUIFactory : public UIFactory {
public:
std::unique_ptr<Button> createButton() override {
return std::make_unique<MacOSButton>();
}

std::unique_ptr<TextBox> createTextBox() override {
return std::make_unique<MacOSTextBox>();
}
};

// 客户端代码:应用程序
class Application {
private:
std::unique_ptr<UIFactory> factory;
std::unique_ptr<Button> button;
std::unique_ptr<TextBox> textBox;

public:
Application(std::unique_ptr<UIFactory> factory) : factory(std::move(factory)) {
// 使用工厂创建UI组件
button = this->factory->createButton();
textBox = this->factory->createTextBox();
}

void initialize() {
textBox->setText("Hello, World!");
}

void render() {
button->render();
textBox->render();
}

void handleClick() {
button->onClick();
}
};

// 使用示例
void useAbstractFactoryPattern() {
// 创建Windows应用程序
std::cout << "=== Windows Application ===" << std::endl;
auto windowsFactory = std::make_unique<WindowsUIFactory>();
Application windowsApp(std::move(windowsFactory));
windowsApp.initialize();
windowsApp.render();
windowsApp.handleClick();

// 创建macOS应用程序
std::cout << "\n=== macOS Application ===" << std::endl;
auto macFactory = std::make_unique<MacOSUIFactory>();
Application macApp(std::move(macFactory));
macApp.initialize();
macApp.render();
macApp.handleClick();
}

优点

  • 保证产品族的一致性,相关产品一起创建
  • 遵循开放封闭原则,添加新产品族时无需修改现有代码
  • 隐藏产品创建细节,客户端只关心产品接口
  • 提高代码的可维护性和可扩展性

缺点

  • 增加了类的数量,系统变得更复杂
  • 添加新产品时需要修改抽象工厂和所有具体工厂
  • 对于简单的对象创建,可能过于繁琐

适用场景

  • 需要创建产品族,且产品族中的产品相互配合使用
  • 系统需要独立于产品的创建、组合和表示
  • 系统需要配置为使用多个产品族中的一个
  • 产品族的一致性很重要,需要确保使用同一产品族的产品

结构型设计模式深度解析

结构型模式专注于类和对象的组合,通过合理的结构设计来实现更灵活、更有效的代码组织。

适配器模式(Adapter)

核心思想:将一个类的接口转换成客户希望的另一个接口。适配器模式使原本由于接口不兼容而不能一起工作的类可以协同工作。

技术实现

  • 类适配器:通过多重继承实现
  • 对象适配器:通过组合实现(更常用)
  • 接口适配:转换接口方法签名
  • 数据适配:转换数据格式

实际应用场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// 目标接口:现代支付系统
class PaymentProcessor {
public:
virtual ~PaymentProcessor() = default;
virtual void processPayment(double amount) = 0;
virtual void refundPayment(double amount) = 0;
virtual bool verifyPayment() = 0;
};

// 适配者:旧版支付系统
class LegacyPaymentSystem {
public:
void makePayment(double amount) {
std::cout << "Legacy system: Processing payment of $" << amount << std::endl;
}

void issueRefund(double amount) {
std::cout << "Legacy system: Issuing refund of $" << amount << std::endl;
}

bool validateTransaction() {
std::cout << "Legacy system: Validating transaction" << std::endl;
return true; // 简化示例
}
};

// 适配者:第三方支付API
class ThirdPartyPaymentAPI {
public:
void submitPayment(double amount, const std::string& currency) {
std::cout << "Third-party API: Submitting payment of " << currency << " " << amount << std::endl;
}

void requestRefund(double amount, const std::string& currency, const std::string& transactionId) {
std::cout << "Third-party API: Requesting refund of " << currency << " " << amount
<< " for transaction " << transactionId << std::endl;
}

bool authenticate() {
std::cout << "Third-party API: Authenticating" << std::endl;
return true; // 简化示例
}
};

// 对象适配器:旧版系统适配器
class LegacyPaymentAdapter : public PaymentProcessor {
private:
LegacyPaymentSystem& legacySystem;

public:
explicit LegacyPaymentAdapter(LegacyPaymentSystem& system) : legacySystem(system) {}

void processPayment(double amount) override {
legacySystem.makePayment(amount);
}

void refundPayment(double amount) override {
legacySystem.issueRefund(amount);
}

bool verifyPayment() override {
return legacySystem.validateTransaction();
}
};

// 对象适配器:第三方API适配器
class ThirdPartyPaymentAdapter : public PaymentProcessor {
private:
ThirdPartyPaymentAPI& thirdPartyAPI;
std::string currency;
std::string transactionId;

public:
ThirdPartyPaymentAdapter(ThirdPartyPaymentAPI& api, std::string currency)
: thirdPartyAPI(api), currency(std::move(currency)), transactionId("TXN" + std::to_string(rand())) {}

void processPayment(double amount) override {
if (verifyPayment()) {
thirdPartyAPI.submitPayment(amount, currency);
}
}

void refundPayment(double amount) override {
thirdPartyAPI.requestRefund(amount, currency, transactionId);
}

bool verifyPayment() override {
return thirdPartyAPI.authenticate();
}
};

// 客户端代码:电子商务系统
class ECommerceSystem {
private:
std::unique_ptr<PaymentProcessor> paymentProcessor;

public:
ECommerceSystem(std::unique_ptr<PaymentProcessor> processor)
: paymentProcessor(std::move(processor)) {}

void checkout(double totalAmount) {
std::cout << "Processing checkout for $" << totalAmount << std::endl;

if (paymentProcessor->verifyPayment()) {
paymentProcessor->processPayment(totalAmount);
std::cout << "Checkout completed successfully" << std::endl;
} else {
std::cout << "Payment verification failed" << std::endl;
}
}

void processRefund(double refundAmount) {
std::cout << "Processing refund for $" << refundAmount << std::endl;
paymentProcessor->refundPayment(refundAmount);
std::cout << "Refund processed successfully" << std::endl;
}
};

// 使用示例
void useAdapterPattern() {
// 使用旧版支付系统
std::cout << "=== Using Legacy Payment System ===" << std::endl;
LegacyPaymentSystem legacySystem;
auto legacyAdapter = std::make_unique<LegacyPaymentAdapter>(legacySystem);
ECommerceSystem legacyStore(std::move(legacyAdapter));
legacyStore.checkout(199.99);
legacyStore.processRefund(50.00);

// 使用第三方支付API
std::cout << "\n=== Using Third-Party Payment API ===" << std::endl;
ThirdPartyPaymentAPI thirdPartyAPI;
auto thirdPartyAdapter = std::make_unique<ThirdPartyPaymentAdapter>(thirdPartyAPI, "USD");
ECommerceSystem modernStore(std::move(thirdPartyAdapter));
modernStore.checkout(299.99);
modernStore.processRefund(75.00);
}

优点

  • 复用现有代码,无需修改适配者
  • 客户端代码统一,无需关心具体实现
  • 遵循开放封闭原则,易于扩展
  • 降低系统间的耦合度

缺点

  • 增加了系统的复杂性
  • 可能引入性能开销(适配层)
  • 对于复杂接口,适配工作可能繁琐

适用场景

  • 集成 legacy 系统到新系统
  • 使用第三方库,但其接口不符合需求
  • 统一多个相似但接口不同的系统
  • 系统演化过程中,接口需要兼容

装饰器模式(Decorator)

核心思想:动态地给一个对象添加一些额外的职责。装饰器模式提供了一种比继承更灵活的方式来扩展对象的功能。

技术实现

  • 组件接口定义核心功能
  • 具体组件实现核心功能
  • 装饰器抽象类继承组件接口并持有组件引用
  • 具体装饰器实现额外功能
  • 支持多层装饰,形成装饰链

实际应用场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// 组件接口:数据流处理器
class DataProcessor {
public:
virtual ~DataProcessor() = default;
virtual std::string process(const std::string& data) = 0;
virtual std::string getName() const = 0;
};

// 具体组件:基础数据处理器
class BaseDataProcessor : public DataProcessor {
public:
std::string process(const std::string& data) override {
std::cout << "Base processor: Processing raw data" << std::endl;
return data;
}

std::string getName() const override {
return "BaseProcessor";
}
};

// 装饰器抽象类
class DataProcessorDecorator : public DataProcessor {
protected:
std::unique_ptr<DataProcessor> processor;

public:
DataProcessorDecorator(std::unique_ptr<DataProcessor> processor)
: processor(std::move(processor)) {}

std::string process(const std::string& data) override {
return processor->process(data);
}

std::string getName() const override {
return processor->getName();
}
};

// 具体装饰器:数据加密器
class EncryptionDecorator : public DataProcessorDecorator {
private:
std::string encrypt(const std::string& data) {
// 简单的加密实现(实际应用中应使用更安全的算法)
std::string encrypted = data;
for (char& c : encrypted) {
c += 1; // 每个字符加1
}
return encrypted;
}

public:
using DataProcessorDecorator::DataProcessorDecorator;

std::string process(const std::string& data) override {
std::string processed = DataProcessorDecorator::process(data);
std::string encrypted = encrypt(processed);
std::cout << "Encryption decorator: Encrypting data" << std::endl;
return encrypted;
}

std::string getName() const override {
return processor->getName() + "+Encryption";
}
};

// 具体装饰器:数据压缩器
class CompressionDecorator : public DataProcessorDecorator {
private:
std::string compress(const std::string& data) {
// 简单的压缩实现(实际应用中应使用更高效的算法)
std::cout << "Compression decorator: Compressing data (original size: " << data.size() << ")" << std::endl;
return "[COMPRESSED]" + data.substr(0, std::min(10, static_cast<int>(data.size()))) + "...";
}

public:
using DataProcessorDecorator::DataProcessorDecorator;

std::string process(const std::string& data) override {
std::string processed = DataProcessorDecorator::process(data);
std::string compressed = compress(processed);
return compressed;
}

std::string getName() const override {
return processor->getName() + "+Compression";
}
};

// 具体装饰器:数据验证器
class ValidationDecorator : public DataProcessorDecorator {
private:
bool validate(const std::string& data) {
std::cout << "Validation decorator: Validating data" << std::endl;
return !data.empty(); // 简单的非空验证
}

public:
using DataProcessorDecorator::DataProcessorDecorator;

std::string process(const std::string& data) override {
if (!validate(data)) {
throw std::runtime_error("Data validation failed");
}
return DataProcessorDecorator::process(data);
}

std::string getName() const override {
return processor->getName() + "+Validation";
}
};

// 使用示例
void useDecoratorPattern() {
// 基础处理器
std::cout << "=== Base Processor ===" << std::endl;
auto baseProcessor = std::make_unique<BaseDataProcessor>();
std::string result1 = baseProcessor->process("Hello, World!");
std::cout << "Result: " << result1 << std::endl;
std::cout << "Processor name: " << baseProcessor->getName() << std::endl;

// 带加密的处理器
std::cout << "\n=== Encryption Processor ===" << std::endl;
auto encryptionProcessor = std::make_unique<EncryptionDecorator>(std::make_unique<BaseDataProcessor>());
std::string result2 = encryptionProcessor->process("Hello, World!");
std::cout << "Result: " << result2 << std::endl;
std::cout << "Processor name: " << encryptionProcessor->getName() << std::endl;

// 带加密和压缩的处理器
std::cout << "\n=== Encryption + Compression Processor ===" << std::endl;
auto encryptedCompressedProcessor = std::make_unique<CompressionDecorator>(
std::make_unique<EncryptionDecorator>(
std::make_unique<BaseDataProcessor>()
)
);
std::string result3 = encryptedCompressedProcessor->process("Hello, World!");
std::cout << "Result: " << result3 << std::endl;
std::cout << "Processor name: " << encryptedCompressedProcessor->getName() << std::endl;

// 带验证、加密和压缩的处理器
std::cout << "\n=== Validation + Encryption + Compression Processor ===" << std::endl;
auto fullyDecoratedProcessor = std::make_unique<ValidationDecorator>(
std::make_unique<CompressionDecorator>(
std::make_unique<EncryptionDecorator>(
std::make_unique<BaseDataProcessor>()
)
)
);
std::string result4 = fullyDecoratedProcessor->process("Hello, World!");
std::cout << "Result: " << result4 << std::endl;
std::cout << "Processor name: " << fullyDecoratedProcessor->getName() << std::endl;

// 测试验证功能
try {
fullyDecoratedProcessor->process("");
} catch (const std::exception& e) {
std::cout << "Expected error: " << e.what() << std::endl;
}
}

优点

  • 遵循开放封闭原则,通过组合扩展功能
  • 避免使用继承导致的类爆炸
  • 支持动态添加和移除功能
  • 可以组合多个装饰器,实现复杂功能
  • 装饰器和组件解耦,提高代码可维护性

缺点

  • 增加了类的数量
  • 装饰链过长时,调试和理解会变得困难
  • 对于不透明的装饰器,可能会隐藏组件的真实类型

适用场景

  • 需要动态、透明地给对象添加功能
  • 功能可以独立扩展,且可以组合使用
  • 避免使用继承导致的类层次结构过于复杂
  • 单一职责原则的体现,每个装饰器只负责一个功能

组合模式(Composite)

核心思想:将对象组合成树形结构以表示”部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

技术实现

  • 组件接口定义叶节点和组合对象的共同操作
  • 叶节点实现基本操作,不包含子节点
  • 组合对象实现操作,并管理子节点集合
  • 支持递归组合,形成树形结构
  • 统一的接口使得客户端可以透明地处理单个对象和组合对象

实际应用场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
// 组件接口:文件系统节点
class FileSystemNode {
public:
virtual ~FileSystemNode() = default;
virtual void display(int indent = 0) = 0;
virtual int getSize() const = 0;
virtual std::string getName() const = 0;
virtual void add(std::unique_ptr<FileSystemNode> node) {}
virtual void remove(const std::string& name) {}
virtual FileSystemNode* find(const std::string& name) { return nullptr; }
};

// 叶节点:文件
class File : public FileSystemNode {
private:
std::string name;
int size;
std::string content;

public:
File(std::string name, int size, std::string content = "")
: name(std::move(name)), size(size), content(std::move(content)) {}

void display(int indent = 0) override {
std::cout << std::string(indent, ' ') << "- " << name << " (" << size << " bytes)" << std::endl;
}

int getSize() const override {
return size;
}

std::string getName() const override {
return name;
}

// 文件不支持添加子节点
void add(std::unique_ptr<FileSystemNode> node) override {
throw std::runtime_error("Cannot add to a file");
}

// 文件不支持移除子节点
void remove(const std::string& name) override {
throw std::runtime_error("Cannot remove from a file");
}
};

// 组合对象:目录
class Directory : public FileSystemNode {
private:
std::string name;
std::vector<std::unique_ptr<FileSystemNode>> children;

public:
explicit Directory(std::string name) : name(std::move(name)) {}

void display(int indent = 0) override {
std::cout << std::string(indent, ' ') << "+ " << name << " (directory)" << std::endl;
for (const auto& child : children) {
child->display(indent + 2);
}
}

int getSize() const override {
int totalSize = 0;
for (const auto& child : children) {
totalSize += child->getSize();
}
return totalSize;
}

std::string getName() const override {
return name;
}

void add(std::unique_ptr<FileSystemNode> node) override {
children.push_back(std::move(node));
}

void remove(const std::string& name) override {
auto it = std::remove_if(children.begin(), children.end(),
[&name](const std::unique_ptr<FileSystemNode>& node) {
return node->getName() == name;
});

if (it != children.end()) {
children.erase(it, children.end());
std::cout << "Removed " << name << " from " << this->name << std::endl;
}
}

FileSystemNode* find(const std::string& name) override {
// 先检查自己
if (this->name == name) {
return this;
}

// 递归检查子节点
for (const auto& child : children) {
FileSystemNode* result = child->find(name);
if (result) {
return result;
}
}

return nullptr;
}

// 获取目录中的所有文件
std::vector<File*> getFiles() {
std::vector<File*> files;
collectFiles(files);
return files;
}

private:
void collectFiles(std::vector<File*>& files) {
for (const auto& child : children) {
if (auto* file = dynamic_cast<File*>(child.get())) {
files.push_back(file);
} else if (auto* dir = dynamic_cast<Directory*>(child.get())) {
dir->collectFiles(files);
}
}
}
};

// 使用示例
void useCompositePattern() {
// 创建文件系统结构
auto root = std::make_unique<Directory>("root");

// 添加文件和子目录
auto etc = std::make_unique<Directory>("etc");
etc->add(std::make_unique<File>("hosts", 1024, "127.0.0.1 localhost"));
etc->add(std::make_unique<File>("passwd", 2048));

auto home = std::make_unique<Directory>("home");
auto user = std::make_unique<Directory>("user");
user->add(std::make_unique<File>("document.txt", 5120, "Hello, World!"));
user->add(std::make_unique<File>("image.jpg", 102400));

auto pictures = std::make_unique<Directory>("pictures");
pictures->add(std::make_unique<File>("vacation.jpg", 204800));
pictures->add(std::make_unique<File>("family.jpg", 153600));

user->add(std::move(pictures));
home->add(std::move(user));

root->add(std::move(etc));
root->add(std::move(home));
root->add(std::make_unique<File>("README.md", 1536, "Project documentation"));

// 显示文件系统结构
std::cout << "=== File System Structure ===" << std::endl;
root->display();

// 计算总大小
std::cout << "\n=== Total Size ===" << std::endl;
std::cout << "Total size of root directory: " << root->getSize() << " bytes" << std::endl;

// 查找文件
std::cout << "\n=== Find Operation ===" << std::endl;
if (auto* found = root->find("hosts")) {
std::cout << "Found: " << found->getName() << " (" << found->getSize() << " bytes)" << std::endl;
}

if (auto* found = root->find("vacation.jpg")) {
std::cout << "Found: " << found->getName() << " (" << found->getSize() << " bytes)" << std::endl;
}

// 移除文件
std::cout << "\n=== Remove Operation ===" << std::endl;
if (auto* homeDir = dynamic_cast<Directory*>(root->find("home"))) {
homeDir->remove("README.md"); // 不存在的文件

if (auto* userDir = dynamic_cast<Directory*>(homeDir->find("user"))) {
userDir->remove("document.txt");
}
}

// 显示修改后的结构
std::cout << "\n=== Updated File System Structure ===" << std::endl;
root->display();

// 计算新的总大小
std::cout << "\n=== Updated Total Size ===" << std::endl;
std::cout << "Total size of root directory: " << root->getSize() << " bytes" << std::endl;
}

优点

  • 统一处理单个对象和组合对象,简化客户端代码
  • 易于添加新的组件类型,符合开放封闭原则
  • 递归组合形成复杂的树形结构
  • 清晰的层次结构,便于理解和维护

缺点

  • 可能使得设计过于一般化,某些操作对叶节点无意义
  • 对于需要区分叶节点和组合对象的场景,可能需要类型检查
  • 递归操作可能导致性能问题(对于非常深的树)

适用场景

  • 表示部分-整体层次结构(如文件系统、组织架构)
  • 客户端需要统一处理单个对象和组合对象
  • 需要递归组合形成复杂结构的场景
  • 组件的添加和移除需要灵活处理的场景

行为型模式

行为型模式专注于对象之间的通信。

观察者模式(Observer)

定义对象间的一种一对多依赖关系,当一个对象状态发生变化时,所有依赖它的对象都得到通知并被自动更新。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
class Observer {
public:
virtual ~Observer() = default;
virtual void update() = 0;
};

class Subject {
public:
virtual ~Subject() = default;
virtual void attach(std::shared_ptr<Observer> observer) {
observers.push_back(observer);
}

virtual void detach(Observer* observer) {
// 移除观察者
}

virtual void notify() {
for (const auto& observer : observers) {
observer->update();
}
}

private:
std::vector<std::shared_ptr<Observer>> observers;
};

class ConcreteSubject : public Subject {
public:
void setState(int state) {
this->state = state;
notify();
}

int getState() const {
return state;
}

private:
int state;
};

class ConcreteObserver : public Observer {
public:
ConcreteObserver(ConcreteSubject& subject) : subject(subject) {
this->subject.attach(std::shared_ptr<Observer>(this));
}

void update() override {
state = subject.getState();
// 处理更新
}

private:
ConcreteSubject& subject;
int state;
};

策略模式(Strategy)

定义一系列算法,把它们封装起来,并且使它们可相互替换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Strategy {
public:
virtual ~Strategy() = default;
virtual void algorithm() = 0;
};

class ConcreteStrategyA : public Strategy {
public:
void algorithm() override { /* 算法A */ }
};

class ConcreteStrategyB : public Strategy {
public:
void algorithm() override { /* 算法B */ }
};

class Context {
public:
void setStrategy(std::unique_ptr<Strategy> strategy) {
this->strategy = std::move(strategy);
}

void executeAlgorithm() {
strategy->algorithm();
}

private:
std::unique_ptr<Strategy> strategy;
};

命令模式(Command)

将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class Command {
public:
virtual ~Command() = default;
virtual void execute() = 0;
virtual void undo() = 0;
};

class Receiver {
public:
void action() { /* 执行操作 */ }
void reverseAction() { /* 撤销操作 */ }
};

class ConcreteCommand : public Command {
public:
ConcreteCommand(Receiver& receiver) : receiver(receiver) {}
void execute() override {
receiver.action();
}
void undo() override {
receiver.reverseAction();
}

private:
Receiver& receiver;
};

class Invoker {
public:
void setCommand(std::unique_ptr<Command> command) {
this->command = std::move(command);
}

void executeCommand() {
command->execute();
}

void undoCommand() {
command->undo();
}

private:
std::unique_ptr<Command> command;
};

面向对象设计最佳实践

1. 合理使用继承

  • 继承是一种”is-a”关系:派生类应该是基类的一种特殊类型
  • 避免过深的继承层次:继承层次应该控制在合理的范围内
  • 优先使用组合而非继承:当派生类和基类之间不是”is-a”关系时,应该使用组合

2. 设计良好的类

  • 单一职责:每个类应该只有一个职责
  • 高内聚:类的成员之间应该高度相关
  • 低耦合:类之间的依赖应该尽可能少
  • 接口简洁:只暴露必要的接口

3. 合理使用设计模式

  • 理解设计模式的适用场景:不同的设计模式适用于不同的场景
  • 不要过度使用设计模式:简单的问题应该用简单的解决方案
  • 灵活应用设计模式:根据具体情况调整设计模式

4. 代码组织

  • 模块化:将代码组织成逻辑模块
  • 命名规范:使用一致的命名规范
  • 注释:添加适当的注释
  • 代码风格:保持一致的代码风格

面向对象设计的挑战

1. 复杂性管理

  • 抽象层次:合理的抽象层次有助于管理复杂性
  • 模块化:将系统分解为模块化的组件
  • 文档:良好的文档有助于理解系统设计

2. 性能考虑

  • 继承与多态的开销:虚函数调用比普通函数调用慢
  • 内存开销:继承层次会增加对象的大小
  • 设计权衡:在设计和性能之间找到平衡点

3. 可测试性

  • 依赖注入:使用依赖注入提高可测试性
  • 接口隔离:使用接口隔离原则提高可测试性
  • 模拟对象:使用模拟对象进行单元测试

示例:面向对象设计的综合应用

图形编辑器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// 抽象图形类
class Shape {
public:
virtual ~Shape() = default;
virtual void draw() = 0;
virtual void move(int x, int y) = 0;
virtual std::unique_ptr<Shape> clone() = 0;
};

// 具体图形类
class Circle : public Shape {
public:
Circle(int x, int y, int radius) : x(x), y(y), radius(radius) {}

void draw() override {
std::cout << "Drawing circle at (" << x << ", " << y << ") with radius " << radius << std::endl;
}

void move(int dx, int dy) override {
x += dx;
y += dy;
}

std::unique_ptr<Shape> clone() override {
return std::make_unique<Circle>(x, y, radius);
}

private:
int x, y, radius;
};

class Rectangle : public Shape {
public:
Rectangle(int x, int y, int width, int height) : x(x), y(y), width(width), height(height) {}

void draw() override {
std::cout << "Drawing rectangle at (" << x << ", " << y << ") with width " << width << " and height " << height << std::endl;
}

void move(int dx, int dy) override {
x += dx;
y += dy;
}

std::unique_ptr<Shape> clone() override {
return std::make_unique<Rectangle>(x, y, width, height);
}

private:
int x, y, width, height;
};

// 图形工厂
class ShapeFactory {
public:
static std::unique_ptr<Shape> createShape(const std::string& type, int x, int y, int... params) {
if (type == "circle") {
return std::make_unique<Circle>(x, y, params[0]);
} else if (type == "rectangle") {
return std::make_unique<Rectangle>(x, y, params[0], params[1]);
}
return nullptr;
}
};

// 图形组合
class ShapeComposite : public Shape {
public:
void addShape(std::unique_ptr<Shape> shape) {
shapes.push_back(std::move(shape));
}

void removeShape(Shape* shape) {
// 移除图形
}

void draw() override {
for (const auto& shape : shapes) {
shape->draw();
}
}

void move(int dx, int dy) override {
for (auto& shape : shapes) {
shape->move(dx, dy);
}
}

std::unique_ptr<Shape> clone() override {
auto composite = std::make_unique<ShapeComposite>();
for (const auto& shape : shapes) {
composite->addShape(shape->clone());
}
return composite;
}

private:
std::vector<std::unique_ptr<Shape>> shapes;
};

// 图形编辑器
class GraphicsEditor {
public:
void addShape(std::unique_ptr<Shape> shape) {
shapes.push_back(std::move(shape));
}

void drawAll() {
for (const auto& shape : shapes) {
shape->draw();
}
}

void moveAll(int dx, int dy) {
for (auto& shape : shapes) {
shape->move(dx, dy);
}
}

private:
std::vector<std::unique_ptr<Shape>> shapes;
};

// 使用示例
void useGraphicsEditor() {
GraphicsEditor editor;

// 添加图形
editor.addShape(ShapeFactory::createShape("circle", 10, 10, 5));
editor.addShape(ShapeFactory::createShape("rectangle", 20, 20, 10, 8));

// 绘制所有图形
editor.drawAll();

// 移动所有图形
editor.moveAll(5, 5);

// 再次绘制所有图形
editor.drawAll();
}

总结

面向对象设计是一种强大的软件开发方法,它通过封装、继承、多态和抽象等概念,帮助开发者创建可维护、可扩展的软件系统。

SOLID原则是面向对象设计的基本原则,它们为创建高质量的软件提供了指导。设计模式是在软件设计中反复出现的问题的解决方案,它们可以帮助开发者更有效地解决常见的设计问题。

在实际开发中,应该根据具体情况灵活应用面向对象设计的原则和模式,在设计和性能之间找到平衡点,创建既优雅又高效的软件系统。