1. 从零开始构建鸭子模拟器:设计模式实战解析
作为一名C++开发者,我最近在重温经典著作《Head First设计模式》。不同于原书的Java实现,我决定用C++重写所有示例,并记录下自己的理解和实践心得。今天要分享的是一个综合运用多种设计模式的鸭子模拟器项目,这个案例完美展示了模式之间如何协同工作。
设计模式不是孤立存在的,在实际开发中,我们经常需要组合使用多种模式来解决复杂问题。这个鸭子模拟器项目就涉及了适配器模式、装饰器模式、抽象工厂模式、组合模式和观察者模式等多种设计模式。让我们一步步拆解这个案例,看看如何用C++实现这些模式的协同工作。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 基础架构:Quackable接口与实现
2.1 定义Quackable接口
首先,我们需要一个统一的接口来表示所有会"呱呱叫"的对象。在C++中,我们可以使用纯虚类来定义这个接口:
cpp复制struct Quackable {
virtual void quack() = 0;
virtual ~Quackable() = default; // 良好的习惯:为多态基类添加虚析构函数
};
这个简单的接口定义了一个quack()方法,所有会叫的鸭子类都需要实现这个方法。使用纯虚函数确保了Quackable是一个抽象接口,不能被直接实例化。
2.2 实现具体的鸭子类
接下来,我们实现几种具体的鸭子类型:
cpp复制class MallardDuck : public Quackable {
public:
void quack() override {
cout << "Quack" << endl;
}
};
class RedheadDuck : public Quackable {
public:
void quack() override {
cout << "Quack" << endl;
}
};
class DuckCall : public Quackable {
public:
void quack() override {
cout << "Kwak" << endl; // 鸭鸣器的声音不同
}
};
class RubberDuck : public Quackable {
public:
void quack() override {
cout << "Squeak" << endl; // 橡皮鸭发出吱吱声
}
};
每种鸭子类都实现了quack()方法,但发出不同的声音。这里体现了面向对象的多态特性——不同类型的鸭子对相同的消息做出不同的响应。
2.3 构建模拟器
有了这些基础类,我们可以构建一个简单的模拟器:
cpp复制void simulate(Quackable* duck) {
duck->quack();
}
void simulate() {
Quackable* mallardDuck = new MallardDuck();
Quackable* redheadDuck = new RedheadDuck();
Quackable* duckCall = new DuckCall();
Quackable* rubberDuck = new RubberDuck();
cout << "Duck Simulator\n";
simulate(mallardDuck);
simulate(redheadDuck);
simulate(duckCall);
simulate(rubberDuck);
// 记得释放内存
delete mallardDuck;
delete redheadDuck;
delete duckCall;
delete rubberDuck;
}
这个基础版本虽然简单,但已经展示了面向对象设计的基本原则:针对接口编程,而不是针对实现编程。
注意:在实际项目中,建议使用智能指针(如
std::unique_ptr)来管理这些动态分配的对象,避免内存泄漏。这里为了代码简洁,使用了原始指针。
3. 扩展功能:适配器模式引入鹅
3.1 鹅类的实现
现在假设我们有一个鹅类,它也能发出声音(虽然叫声不同):
cpp复制class Goose {
public:
void honk() {
cout << "Honk" << endl; // 鹅的叫声是"Honk"
}
};
3.2 适配器模式的应用
我们希望在不修改鹅类的情况下,让鹅也能在模拟器中作为Quackable对象使用。这时适配器模式就派上用场了:
cpp复制class GooseAdapter : public Quackable {
public:
GooseAdapter(Goose* g) : goose(g) {}
void quack() override {
goose->honk(); // 将quack调用适配为honk调用
}
private:
Goose* goose; // 被适配的对象
};
适配器模式将一个类的接口转换成客户端期望的另一个接口,使得原本不兼容的类可以一起工作
