迭代器模式提供一种方法来顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。该模式将遍历逻辑封装在迭代器对象中,使聚合对象和遍历逻辑分离。
核心组件:
场景:实现一个简单的数组集合,并为其提供迭代器支持。
#include
#include
// 前向声明
template<typename T> class ArrayIterator;
// 迭代器接口
template<typename T>
class Iterator {
public:
virtual ~Iterator() = default;
virtual bool hasNext() const = 0;
virtual T& next() = 0;
virtual const T& next() const = 0;
};
// 聚合接口
template<typename T>
class Aggregate {
public:
virtual ~Aggregate() = default;
virtual std::unique_ptr<Iterator<T>> createIterator() const = 0;
virtual size_t size() const = 0;
virtual T& operator[](size_t index) = 0;
virtual const T& operator[](size_t index) const = 0;
};
// 具体聚合:数组集合
template<typename T, size_t N>
class Array : public Aggregate<T> {
private:
T data[N];
size_t count = 0;
public:
void add(const T& item) {
if (count < N) {
data[count++] = item;
}
}
size_t size() const override { return count; }
T& operator[](size_t index) override { return data[index]; }
const T& operator[](size_t index) const override { return data[index]; }
std::unique_ptr<Iterator<T>> createIterator() const override;
};
// 具体迭代器:数组迭代器
template<typename T, size_t N>
class ArrayIterator : public Iterator<T> {
private:
const Array<T, N>* array;
size_t position;
public:
explicit ArrayIterator(const Array<T, N>* array)
: array(array), position(0) {}
bool hasNext() const override {
return position < array->size();
}
T& next() override {
return (*array)[position++];
}
const T& next() const override {
return (*array)[position++];
}
};
// 实现createIterator方法
template<typename T, size_t N>
std::unique_ptr<Iterator<T>> Array<T, N>::createIterator() const {
return std::make_unique<ArrayIterator<T, N>>(this);
}
// 客户端代码
int main() {
Array<int, 5> numbers;
numbers.add(10);
numbers.add(20);
numbers.add(30);
// 使用迭代器遍历集合
auto it = numbers.createIterator();
while (it->hasNext()) {
std::cout << it->next() << " ";
}
std::cout << std::endl;
// C++范围for循环风格(需额外实现begin/end)
// 此处省略具体实现...
return 0;
}
分离遍历逻辑:
简化聚合接口:
支持多种遍历方式:
统一访问接口:
内部迭代器 vs 外部迭代器:
双向迭代器:
prev()
方法)。流式迭代器:
组合迭代器:
隐藏聚合实现:
支持多种遍历方式:
统一遍历接口:
简化客户端代码:
迭代器失效:
线程安全:
与语言特性结合:
std::iterator
和容器迭代器,优先使用现有实现。性能开销:
与访问者模式的区别:
与组合模式的结合:
与生成器模式的关系:
迭代器模式是处理聚合对象遍历的经典解决方案,通过将遍历逻辑封装在迭代器中,使代码更简洁、灵活且易于维护。在实际开发中,建议优先使用编程语言提供的内置迭代器(如 C++ 的 STL 迭代器),避免重复造轮子。
单例模式确保一个类只有一个实例,并提供一个全局访问点来获取该实例。该模式常用于需要全局唯一对象的场景,如配置管理器、日志记录器、数据库连接池等。
核心组件:
// 线程不安全版本(单线程环境)
class Singleton {
private:
static Singleton* instance;
Singleton() = default; // 私有构造函数
~Singleton() = default; // 私有析构函数
Singleton(const Singleton&) = delete; // 禁用拷贝构造
Singleton& operator=(const Singleton&) = delete; // 禁用赋值运算符
public:
static Singleton* getInstance() {
if (instance == nullptr) { // 第一次调用时初始化
instance = new Singleton();
}
return instance;
}
};
// 静态成员初始化
Singleton* Singleton::instance = nullptr;
#include
class Singleton {
private:
static Singleton* instance;
static std::mutex mutex_;
Singleton() = default;
public:
static Singleton* getInstance() {
if (instance == nullptr) { // 第一次检查
std::lock_guard<std::mutex> lock(mutex_);
if (instance == nullptr) { // 第二次检查(锁内)
instance = new Singleton();
}
}
return instance;
}
};
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mutex_;
class Singleton {
private:
static const Singleton* instance;
Singleton() = default;
public:
static const Singleton* getInstance() {
return instance;
}
};
// 静态初始化(在main函数前完成)
const Singleton* Singleton::instance = new Singleton();
class Singleton {
private:
Singleton() = default;
~Singleton() = default;
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
public:
static Singleton& getInstance() {
static Singleton instance; // 线程安全的局部静态变量
return instance;
}
};
全局唯一性:
全局访问点:
延迟初始化:
严格控制访问:
多线程安全:
可销毁单例:
模板单例:
参数化单例:
资源管理器:
配置管理:
日志系统:
GUI 组件:
线程安全:
内存泄漏:
反序列化问题:
继承与多态:
与静态类的区别:
与工厂模式的结合:
与享元模式的区别:
单例模式是解决全局唯一对象需求的经典方案,但需谨慎使用,避免滥用导致代码耦合度高。在现代 C++ 中,推荐使用 Meyers’ Singleton 实现,既简洁又安全。
合成/聚合复用原则(Composition/Aggregation Reuse Principle, CARP)主张:
“要尽量使用合成/聚合,而不是类继承来达到复用的目的”。
std::unique_ptr
)。std::shared_ptr
或引用)。该原则强调通过对象组合实现复用,而非通过继承扩展类功能,以降低代码耦合度。
维度 | 合成/聚合(推荐) | 继承(需谨慎) |
---|---|---|
耦合度 | 低(对象间松耦合) | 高(子类依赖父类实现) |
灵活性 | 运行时动态组合,支持多态 | 编译时静态绑定,难以修改 |
复用粒度 | 细粒度(复用具体组件) | 粗粒度(复用整个父类) |
依赖可见性 | 仅依赖接口,不暴露内部实现 | 可能暴露父类非公共接口 |
设计模式 | 策略模式、装饰器模式、组合模式 | 模板方法模式、工厂方法模式 |
// 父类:引擎
class Engine {
public:
void start() { std::cout << "引擎启动" << std::endl; }
void stop() { std::cout << "引擎停止" << std::endl; }
};
// 子类:汽车(继承引擎)
class Car : public Engine {
public:
void drive() {
start(); // 直接复用父类方法
std::cout << "汽车行驶" << std::endl;
stop();
}
};
// 子类:飞机(继承引擎)
class Plane : public Engine {
public:
void fly() {
start(); // 直接复用父类方法
std::cout << "飞机起飞" << std::endl;
stop();
}
};
问题:
Car
和Plane
与Engine
强绑定,无法在运行时更换引擎类型。Engine
修改接口,所有子类需同步修改。// 接口:引擎
class IEngine {
public:
virtual void start() = 0;
virtual void stop() = 0;
virtual ~IEngine() = default;
};
// 具体引擎:燃油引擎
class GasolineEngine : public IEngine {
public:
void start() override { std::cout << "燃油引擎启动" << std::endl; }
void stop() override { std::cout << "燃油引擎停止" << std::endl; }
};
// 具体引擎:电动引擎
class ElectricEngine : public IEngine {
public:
void start() override { std::cout << "电动引擎启动" << std::endl; }
void stop() override { std::cout << "电动引擎停止" << std::endl; }
};
// 交通工具(聚合引擎)
class Vehicle {
private:
std::unique_ptr<IEngine> engine; // 聚合:组合关系
public:
explicit Vehicle(std::unique_ptr<IEngine> engine)
: engine(std::move(engine)) {}
void setEngine(std::unique_ptr<IEngine> newEngine) {
engine = std::move(newEngine);
}
void operate() {
engine->start();
std::cout << "交通工具运行" << std::endl;
engine->stop();
}
};
// 客户端代码
void clientCode() {
// 使用燃油引擎
auto car = Vehicle(std::make_unique<GasolineEngine>());
car.operate();
// 动态更换为电动引擎
car.setEngine(std::make_unique<ElectricEngine>());
car.operate();
}
优势:
IEngine
接口,Vehicle
与具体引擎实现解耦。策略模式(Strategy Pattern)
通过组合不同策略对象实现算法切换:
class SortStrategy {
public:
virtual void sort(std::vector<int>& data) = 0;
};
class QuickSort : public SortStrategy { /* 实现 */ };
class MergeSort : public SortStrategy { /* 实现 */ };
class Sorter {
private:
std::unique_ptr<SortStrategy> strategy;
public:
void setStrategy(std::unique_ptr<SortStrategy> s) {
strategy = std::move(s);
}
void performSort(std::vector<int>& data) {
strategy->sort(data);
}
};
装饰器模式(Decorator Pattern)
通过组合增强对象功能:
class Component {
public:
virtual void operation() = 0;
};
class ConcreteComponent : public Component { /* 基础实现 */ };
class Decorator : public Component {
protected:
std::shared_ptr<Component> component;
public:
explicit Decorator(std::shared_ptr<Component> c) : component(c) {}
};
class LoggingDecorator : public Decorator {
public:
void operation() override {
std::cout << "Before operation" << std::endl;
component->operation();
std::cout << "After operation" << std::endl;
}
};
优先使用合成/聚合的场景:
继承的合理场景:
黄金法则:
过度组合导致的问题:
与依赖倒置原则(DIP)结合:
继承的替代方案:
合成/聚合复用原则是实现低耦合、高内聚设计的关键,它通过对象组合替代继承,使系统更灵活、可维护和可扩展。在设计时,应根据具体场景权衡继承与组合的使用,避免过度依赖单一复用方式。
在C++中,无法在运行时动态确定子类继承自哪个基类。这是因为C++的继承关系是静态绑定的,必须在编译时明确指定。不过,你可以通过以下几种方式模拟运行时选择基类的行为:
编译时确定内存布局:
子类的内存布局(包括基类子对象的偏移量)在编译时必须确定,否则无法进行对象访问。
静态类型系统限制:
C++的类型系统要求在编译时明确类的继承结构,以保证类型安全。
思路:在子类中包含基类指针,运行时动态选择基类实现。
#include
// 基接口
class Base {
public:
virtual void doSomething() = 0;
virtual ~Base() = default;
};
// 具体实现类A
class ConcreteA : public Base {
public:
void doSomething() override { /* 实现A */ }
};
// 具体实现类B
class ConcreteB : public Base {
public:
void doSomething() override { /* 实现B */ }
};
// 动态选择行为的类
class DynamicClass {
private:
std::unique_ptr<Base> strategy; // 组合基类指针
public:
// 在运行时设置行为
void setStrategy(std::unique_ptr<Base> strategy) {
this->strategy = std::move(strategy);
}
// 委托调用
void performAction() {
if (strategy) strategy->doSomething();
}
};
// 运行时选择示例
void runtimeSelection(bool condition) {
DynamicClass obj;
if (condition) {
obj.setStrategy(std::make_unique<ConcreteA>());
} else {
obj.setStrategy(std::make_unique<ConcreteB>());
}
obj.performAction(); // 根据condition选择不同实现
}
思路:通过模板参数在编译时选择基类。
// 基类A
class BaseA {
public:
void method() { /* 基类A的实现 */ }
};
// 基类B
class BaseB {
public:
void method() { /* 基类B的实现 */ }
};
// 模板子类:编译时选择基类
template<typename BaseType>
class Derived : public BaseType {
public:
void callBaseMethod() {
this->method(); // 调用所选基类的方法
}
};
// 编译时选择示例
void compileTimeSelection(bool condition) {
if (condition) {
Derived<BaseA> obj; // 继承自BaseA
obj.callBaseMethod();
} else {
Derived<BaseB> obj; // 继承自BaseB
obj.callBaseMethod();
}
}
思路:继承所有可能的基类,运行时通过接口选择具体行为。
// 接口A
class InterfaceA {
public:
virtual void actionA() = 0;
};
// 接口B
class InterfaceB {
public:
virtual void actionB() = 0;
};
// 实现类同时继承两个接口
class MultiBase : public InterfaceA, public InterfaceB {
public:
void actionA() override { /* 实现A */ }
void actionB() override { /* 实现B */ }
};
// 运行时选择接口
void runtimeInterfaceSelection(bool useA) {
MultiBase obj;
if (useA) {
InterfaceA* ptr = &obj;
ptr->actionA(); // 使用接口A
} else {
InterfaceB* ptr = &obj;
ptr->actionB(); // 使用接口B
}
}
思路:通过插件系统在运行时加载不同的实现库。
// 公共接口
class PluginInterface {
public:
virtual void execute() = 0;
virtual ~PluginInterface() = default;
};
// 插件工厂(简化版)
class PluginFactory {
public:
static std::unique_ptr<PluginInterface> createPlugin(const std::string& name) {
// 实际实现中通过动态库加载
if (name == "A") return std::make_unique<PluginA>();
if (name == "B") return std::make_unique<PluginB>();
return nullptr;
}
};
// 运行时加载插件
void loadPluginAtRuntime(const std::string& pluginName) {
auto plugin = PluginFactory::createPlugin(pluginName);
if (plugin) plugin->execute();
}
方案 | 实现方式 | 绑定时机 | 灵活性 | 复杂度 |
---|---|---|---|---|
组合替代继承 | 持有基类指针 | 运行时 | 高 | 中 |
模板 | 模板参数选择基类 | 编译时 | 中 | 低 |
多重继承 | 继承所有基类,选接口使用 | 运行时 | 中 | 高 |
动态加载插件 | 运行时加载动态库 | 运行时 | 极高 | 高 |
根据具体需求,选择合适的替代方案来模拟“运行时选择基类”的行为。