第13章 类与封装

面向对象设计概述

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

硬件感知的面向对象设计

现代C++编程需要考虑硬件特性,以实现最佳性能:

  1. 缓存友好的类设计

    • 成员变量的布局应考虑CPU缓存行大小(通常为64字节)
    • 将频繁访问的成员放在一起,减少缓存未命中
    • 避免伪共享(False Sharing)现象,特别是在多线程环境中
  2. 内存对齐优化

    • 使用alignas关键字指定成员变量的对齐要求
    • 合理安排成员变量顺序,减少内存空洞
    • 对于需要特定对齐的类型(如SIMD类型),确保正确对齐
  3. 分支预测友好的设计

    • 避免在热点代码中使用多态(虚函数调用)
    • 考虑使用CRTP(奇异递归模板模式)实现静态多态
    • 使用if constexpr(C++17+)在编译期消除分支
  4. SIMD友好的类设计

    • 对于需要向量化的类,提供适合SIMD操作的接口
    • 考虑数据布局的向量化友好性
    • 使用C++20的span实现连续内存访问

现代C++的封装特性

  1. 强类型枚举(C++11+)

    1
    2
    3
    enum class Color : uint8_t {
    Red, Green, Blue
    };
    • 避免命名空间污染
    • 提供更好的类型安全
    • 支持指定底层类型,节省内存
  2. 内联变量(C++17+)

    1
    2
    3
    4
    5
    class Config {
    public:
    inline static const int MaxConnections = 100;
    inline static const std::string DefaultName = "config";
    };
    • 避免头文件中的定义问题
    • 简化静态成员的初始化
    • 支持非整型静态成员的类内初始化
  3. 结构化绑定(C++17+)

    1
    2
    3
    4
    5
    6
    struct Point {
    int x, y;
    };

    Point p = {10, 20};
    auto [x, y] = p; // 结构化绑定
    • 方便地从对象中提取多个成员
    • 提高代码可读性
    • 与tuple和pair无缝集成
  4. 类模板参数推导(C++17+)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    template <typename T>
    class MyContainer {
    public:
    MyContainer(T value) : data(value) {}
    private:
    T data;
    };

    // C++17+ 自动推导模板参数
    MyContainer c(42); // 自动推导为 MyContainer<int>
  5. 概念(Concepts,C++20+)

    1
    2
    3
    4
    5
    6
    7
    template <typename T>
    concept Numeric = std::is_arithmetic_v<T>;

    template <Numeric T>
    class Calculator {
    // 实现
    };
    • 约束模板参数
    • 提供更清晰的错误信息
    • 简化模板代码

高级封装技巧

  1. Pimpl模式(Pointer to Implementation)

    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
    // header file
    class Widget {
    private:
    class Impl;
    std::unique_ptr<Impl> pImpl;
    public:
    Widget();
    ~Widget();
    void doSomething();
    };

    // cpp file
    class Widget::Impl {
    private:
    int data;
    std::string name;
    public:
    void doSomething() {
    // 实现
    }
    };

    Widget::Widget() : pImpl(std::make_unique<Impl>()) {}
    Widget::~Widget() = default;
    void Widget::doSomething() { pImpl->doSomething(); }
    • 减少头文件依赖
    • 加快编译速度
    • 隐藏实现细节
    • 支持二进制兼容性
  2. 桥接模式(Bridge Pattern)

    • 将抽象与实现分离
    • 支持运行时切换实现
    • 减少子类数量
  3. 策略模式的现代实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    class SortStrategy {
    public:
    virtual ~SortStrategy() = default;
    virtual void sort(std::vector<int>& data) = 0;
    };

    class QuickSort : public SortStrategy {
    public:
    void sort(std::vector<int>& data) override {
    // 快速排序实现
    }
    };

    class Sorter {
    private:
    std::unique_ptr<SortStrategy> strategy;
    public:
    Sorter(std::unique_ptr<SortStrategy> strat) : strategy(std::move(strat)) {}
    void sort(std::vector<int>& data) {
    strategy->sort(data);
    }
    };
  4. 混入(Mixin)模式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    template <typename Base>
    class Loggable : public Base {
    public:
    void log(const std::string& message) {
    std::cout << "[LOG] " << message << std::endl;
    }
    };

    template <typename Base>
    class Serializable : public Base {
    public:
    std::string serialize() {
    return "serialized";
    }
    };

    class MyClass {
    // 基本实现
    };

    using EnhancedMyClass = Loggable<Serializable<MyClass>>;
    • 提供灵活的功能组合
    • 避免多重继承的问题
    • 提高代码复用性

性能优化案例

内存布局优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 优化前:内存布局不佳
class BadLayout {
private:
bool flag; // 1字节
double value; // 8字节
char c; // 1字节
int count; // 4字节
// 总大小:24字节(由于对齐)
};

// 优化后:内存布局紧凑
class GoodLayout {
private:
double value; // 8字节
int count; // 4字节
char c; // 1字节
bool flag; // 1字节
// 总大小:16字节(减少了8字节)
};

虚函数优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 优化前:使用虚函数
class Shape {
public:
virtual void draw() = 0;
virtual ~Shape() = default;
};

// 优化后:使用CRTP静态多态
template <typename Derived>
class ShapeCRTP {
public:
void draw() {
static_cast<Derived*>(this)->drawImpl();
}
};

class Circle : public ShapeCRTP<Circle> {
public:
void drawImpl() {
// 实现
}
};

小对象优化

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
class SmallString {
private:
static constexpr size_t SmallBufferSize = 15;

union {
char smallBuffer[SmallBufferSize + 1];
std::unique_ptr<char[]> largeBuffer;
} buffer;

size_t size;
bool isSmall;

public:
SmallString(const char* str) {
size = strlen(str);
if (size <= SmallBufferSize) {
isSmall = true;
strcpy(buffer.smallBuffer, str);
} else {
isSmall = false;
buffer.largeBuffer = std::make_unique<char[]>(size + 1);
strcpy(buffer.largeBuffer.get(), str);
}
}

// 其他方法...
};

实际工程应用

高性能网络服务器设计

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
class Connection {
private:
int fd;
std::array<char, 4096> buffer; // 固定大小缓冲区,避免动态分配
size_t bufferSize;

public:
explicit Connection(int socket) : fd(socket), bufferSize(0) {}

ssize_t readData() {
ssize_t n = read(fd, buffer.data() + bufferSize, buffer.size() - bufferSize);
if (n > 0) {
bufferSize += n;
}
return n;
}

// 其他方法...
};

class ConnectionManager {
private:
std::unordered_map<int, std::unique_ptr<Connection>> connections;
mutable std::mutex mutex;

public:
void addConnection(int fd, std::unique_ptr<Connection> conn) {
std::lock_guard<std::mutex> lock(mutex);
connections[fd] = std::move(conn);
}

void removeConnection(int fd) {
std::lock_guard<std::mutex> lock(mutex);
connections.erase(fd);
}

Connection* getConnection(int fd) {
std::lock_guard<std::mutex> lock(mutex);
auto it = connections.find(fd);
return (it != connections.end()) ? it->second.get() : nullptr;
}
};

游戏引擎核心设计

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
template <typename Component>
class ComponentManager {
private:
std::vector<Component> components;
std::vector<size_t> freeIndices;

public:
template <typename... Args>
size_t create(Args&&... args) {
if (!freeIndices.empty()) {
size_t index = freeIndices.back();
freeIndices.pop_back();
components[index] = Component(std::forward<Args>(args)...);
return index;
} else {
components.emplace_back(std::forward<Args>(args)...);
return components.size() - 1;
}
}

void destroy(size_t index) {
freeIndices.push_back(index);
}

Component& get(size_t index) {
return components[index];
}
};

class Entity {
private:
size_t id;
std::unordered_map<size_t, size_t> componentIndices;

public:
explicit Entity(size_t entityId) : id(entityId) {}

template <typename Component, typename... Args>
void addComponent(ComponentManager<Component>& manager, Args&&... args) {
size_t index = manager.create(std::forward<Args>(args)...);
componentIndices[typeid(Component).hash_code()] = index;
}

template <typename Component>
Component& getComponent(ComponentManager<Component>& manager) {
size_t hash = typeid(Component).hash_code();
return manager.get(componentIndices[hash]);
}
};

面向对象设计的核心原则

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

面向对象设计的价值

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

类设计与封装原则

SOLID设计原则深度解析

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

异常安全的封装设计

异常安全级别

  1. 无抛出保证(No-throw guarantee):操作不会抛出异常
  2. 强异常安全保证(Strong exception safety):如果操作抛出异常,程序状态不变
  3. 基本异常安全保证(Basic exception safety):如果操作抛出异常,程序状态有效但可能改变
  4. 无保证(No guarantee):如果操作抛出异常,程序可能处于无效状态

实现强异常安全保证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class SafeVector {
private:
std::vector<int> data;

public:
void push_back(int value) {
// 强异常安全保证:如果抛出异常,data不变
data.push_back(value); // vector::push_back 提供强异常安全保证
}

void insert(size_t pos, int value) {
// 强异常安全保证
std::vector<int> temp = data; // 拷贝当前状态
temp.insert(temp.begin() + pos, value); // 在拷贝上操作
data.swap(temp); // 无抛出交换
}
};

资源管理与异常安全

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
class ResourceManager {
private:
int* resource;

public:
ResourceManager(size_t size) : resource(new int[size]) {}

// 析构函数:保证资源释放
~ResourceManager() {
delete[] resource;
}

// 拷贝构造函数:强异常安全保证
ResourceManager(const ResourceManager& other) : resource(nullptr) {
try {
resource = new int[other.size()];
std::copy(other.resource, other.resource + other.size(), resource);
} catch (...) {
delete[] resource;
throw;
}
}

// 移动构造函数:无抛出保证
ResourceManager(ResourceManager&& other) noexcept : resource(other.resource) {
other.resource = nullptr;
}

// 拷贝赋值运算符:强异常安全保证
ResourceManager& operator=(const ResourceManager& other) {
if (this != &other) {
int* temp = new int[other.size()];
try {
std::copy(other.resource, other.resource + other.size(), temp);
} catch (...) {
delete[] temp;
throw;
}
delete[] resource;
resource = temp;
}
return *this;
}

// 移动赋值运算符:无抛出保证
ResourceManager& operator=(ResourceManager&& other) noexcept {
if (this != &other) {
delete[] resource;
resource = other.resource;
other.resource = nullptr;
}
return *this;
}

size_t size() const {
// 实现
return 0;
}
};

线程安全的封装设计

线程安全的单例模式

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
class ThreadSafeSingleton {
private:
static std::unique_ptr<ThreadSafeSingleton> instance;
static std::once_flag initFlag;

ThreadSafeSingleton() {
// 初始化
}

public:
static ThreadSafeSingleton& getInstance() {
std::call_once(initFlag, []() {
instance = std::make_unique<ThreadSafeSingleton>();
});
return *instance;
}

// 删除拷贝和移动操作
ThreadSafeSingleton(const ThreadSafeSingleton&) = delete;
ThreadSafeSingleton& operator=(const ThreadSafeSingleton&) = delete;
ThreadSafeSingleton(ThreadSafeSingleton&&) = delete;
ThreadSafeSingleton& operator=(ThreadSafeSingleton&&) = delete;
};

// 静态成员初始化
std::unique_ptr<ThreadSafeSingleton> ThreadSafeSingleton::instance = nullptr;
std::once_flag ThreadSafeSingleton::initFlag;

线程安全的数据结构

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
class ThreadSafeQueue {
private:
std::queue<int> queue;
mutable std::mutex mutex;
std::condition_variable condVar;

public:
void push(int value) {
{
std::lock_guard<std::mutex> lock(mutex);
queue.push(value);
} // 释放锁
condVar.notify_one(); // 通知等待线程
}

bool tryPop(int& value) {
std::lock_guard<std::mutex> lock(mutex);
if (queue.empty()) {
return false;
}
value = queue.front();
queue.pop();
return true;
}

void waitAndPop(int& value) {
std::unique_lock<std::mutex> lock(mutex);
condVar.wait(lock, [this]() { return !queue.empty(); });
value = queue.front();
queue.pop();
}

bool empty() const {
std::lock_guard<std::mutex> lock(mutex);
return queue.empty();
}
};

现代C++的高级特性

协变返回类型与智能指针

1
2
3
4
5
6
7
8
9
10
11
12
class Base {
public:
virtual ~Base() = default;
virtual std::unique_ptr<Base> clone() const = 0;
};

class Derived : public Base {
public:
std::unique_ptr<Derived> clone() const override {
return std::make_unique<Derived>(*this);
}
};

委托构造函数与继承构造函数

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
class Person {
private:
std::string name;
int age;
std::string address;

public:
// 主构造函数
Person(const std::string& n, int a, const std::string& addr)
: name(n), age(a), address(addr) {}

// 委托构造函数
Person() : Person("Unknown", 0, "Unknown") {}
Person(const std::string& n) : Person(n, 0, "Unknown") {}
};

class Employee : public Person {
private:
std::string employeeId;
double salary;

public:
// 继承Person的构造函数
using Person::Person;

// 额外的构造函数
Employee(const std::string& n, int a, const std::string& addr,
const std::string& id, double s)
: Person(n, a, addr), employeeId(id), salary(s) {}
};

内联变量与constexpr

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Math {
public:
inline static constexpr double PI = 3.14159265358979323846;
inline static constexpr double E = 2.71828182845904523536;

constexpr static double square(double x) {
return x * x;
}

constexpr static double cube(double x) {
return x * x * x;
}
};

// 编译期计算
constexpr double area = Math::PI * Math::square(10.0);

性能优化的深度案例

编译器优化提示

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
class OptimizedClass {
private:
int value;

public:
// 强制内联
[[gnu::always_inline]] inline int getValue() const {
return value;
}

// 告诉编译器这个函数不会抛出异常
[[noreturn]] void fatalError() {
throw std::runtime_error("Fatal error");
}

// 告诉编译器这个函数的参数不会是nullptr
void processNonNullPointer([[maybe_unused]] int* ptr) {
// 实现
}

// 告诉编译器这个函数的返回值可能被忽略
[[nodiscard]] int calculate() const {
return value * 2;
}
};

SIMD优化的类设计

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
#ifdef __AVX2__
class SIMDVector {
private:
alignas(32) float data[8]; // AVX2 512位对齐

public:
SIMDVector() {
std::memset(data, 0, sizeof(data));
}

SIMDVector(float x, float y, float z, float w) {
data[0] = x;
data[1] = y;
data[2] = z;
data[3] = w;
data[4] = data[5] = data[6] = data[7] = 0.0f;
}

// AVX2 向量加法
SIMDVector operator+(const SIMDVector& other) const {
SIMDVector result;
__m256 a = _mm256_load_ps(data);
__m256 b = _mm256_load_ps(other.data);
__m256 c = _mm256_add_ps(a, b);
_mm256_store_ps(result.data, c);
return result;
}

// AVX2 向量乘法
SIMDVector operator*(const SIMDVector& other) const {
SIMDVector result;
__m256 a = _mm256_load_ps(data);
__m256 b = _mm256_load_ps(other.data);
__m256 c = _mm256_mul_ps(a, b);
_mm256_store_ps(result.data, c);
return result;
}

// 获取标量值
float operator[](size_t index) const {
return data[index];
}
};
#endif

实际工程中的最佳实践

依赖注入

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
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 {
// 实现
}

void executeQuery(const std::string& query) override {
// 实现
}
};

class UserService {
private:
std::unique_ptr<Database> db;

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

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

// 使用
auto db = std::make_unique<MySQLDatabase>();
UserService userService(std::move(db));

类型擦除

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
class Any {
private:
struct Base {
virtual ~Base() = default;
virtual std::unique_ptr<Base> clone() const = 0;
};

template <typename T>
struct Derived : Base {
T value;

explicit Derived(T v) : value(std::move(v)) {}

std::unique_ptr<Base> clone() const override {
return std::make_unique<Derived<T>>(value);
}
};

std::unique_ptr<Base> impl;

public:
template <typename T>
Any(T value) : impl(std::make_unique<Derived<T>>(std::move(value))) {}

Any(const Any& other) : impl(other.impl->clone()) {}
Any& operator=(const Any& other) {
impl = other.impl->clone();
return *this;
}

template <typename T>
T& get() {
return static_cast<Derived<T>*>(impl.get())->value;
}
};

策略模式的lambda实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Sorter {
private:
std::function<void(std::vector<int>&)> strategy;

public:
Sorter(std::function<void(std::vector<int>&)> strat) : strategy(std::move(strat)) {}

void sort(std::vector<int>& data) {
strategy(data);
}
};

// 使用lambda作为策略
Sorter bubbleSorter([](std::vector<int>& data) {
// 冒泡排序实现
});

Sorter quickSorter([](std::vector<int>& data) {
// 快速排序实现
});

专家级设计技巧

  1. 接口隔离

    • 将大接口拆分为多个小接口
    • 减少类之间的耦合
    • 提高代码的可维护性
  2. 依赖倒置

    • 高层模块不应该依赖低层模块
    • 两者都应该依赖抽象
    • 抽象不应该依赖细节
  3. 组合优于继承

    • 优先使用对象组合而不是类继承
    • 提高代码的灵活性
    • 减少继承层次的复杂性
  4. 最小知识原则

    • 一个对象应该对其他对象有尽可能少的了解
    • 减少对象之间的直接交互
    • 提高代码的可维护性
  5. 开闭原则

    • 软件实体应该对扩展开放,对修改关闭
    • 通过抽象和多态实现
    • 提高代码的可扩展性
  6. 单一职责原则

    • 一个类应该只有一个引起它变化的原因
    • 提高代码的可维护性
    • 减少类之间的耦合
  7. 里氏替换原则

    • 子类应该可以替换其父类
    • 确保继承层次的正确性
    • 支持多态的正确使用
  8. 防御性编程

    • 假设输入是不可信的
    • 进行充分的错误检查
    • 确保代码的健壮性

总结

面向对象设计是C++编程中的核心范式,它通过封装、继承、多态等机制,提供了一种组织和管理代码的有效方式。现代C++为面向对象设计带来了许多新特性,如移动语义、智能指针、constexpr、概念等,这些特性使得面向对象设计更加灵活、高效和安全。

在实际应用中,我们应该根据具体的场景选择合适的设计模式和技术,结合面向对象设计、函数式编程和泛型编程的优势,以实现高质量、高性能的代码。同时,我们也应该关注硬件特性,优化代码的内存布局和执行路径,以充分发挥现代硬件的性能潜力。

通过不断学习和实践,我们可以掌握面向对象设计的精髓,设计出更加优雅、高效、可维护的C++代码。

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

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