目录
- 设计模式
-
- [单例模式 (Singleton)](#单例模式 (Singleton))
- [工厂方法模式(Factory Method)](#工厂方法模式(Factory Method))
- [适配器模式 (Adapter)](#适配器模式 (Adapter))
- [外观模式 (Facade)](#外观模式 (Facade))
- 代理模式(Proxy)
- 桥接模式(Bridge)
- 装饰器模式(包装模式)(Decorator)
- [模版方法模式(Template Method)](#模版方法模式(Template Method))
- 策略模式(Strategy)
- 观察者模式(Observer)
- [责任链模式(Chain of Responsibility)](#责任链模式(Chain of Responsibility))
开闭原则
开闭原则(Open/Closed Principle)指出软件实体(类、模块、函数等)应该对扩展开放,但对修改关闭
合成复用原则
组合大于继承
设计模式
设计模式通常分为三种主要类型:创建型设计模式、结构型设计模式和行为型设计模式
-
常见的创建型设计模式包括:
-
单例模式(Singleton):确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。
用于控制资源的访问,如数据库连接或文件系统。
-
工厂方法模式(Factory Method):定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。常用于将对象创建的逻辑从应用逻辑中分离出来。
-
抽象工厂模式(Abstract Factory):提供一个接口,用于创建相关的或依赖对象的家族,而不需要明确指定具体类。适用于系统需要处理多系列产品,但希望客户端无需关心具体实现的情况。
-
建造者模式(Builder):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。通常用于创建复杂对象,允许用户按步骤指定复杂对象的各个部分,在用户代码中隔离复杂对象的创建和组装过程。
-
原型模式(Prototype):用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
适用于创建重复对象时,效率更高的场景。
-
-
常见的结构型设计模式包括:
- 适配器模式(Adapter):允许将一个类的接口转换成客户期望的另一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
- 装饰器模式(Decorator):动态地给一个对象添加一些额外的职责,就增加功能来说,装饰器模式比生成子类更为灵活。
- 代理模式(Proxy):为其他对象提供一种代理以控制对这个对象的访问。
- 桥接模式(Bridge):将抽象部分与实现部分分离,使它们都可以独立地变化。
- 外观模式(Facade):为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
- 组合模式(Composite):将对象组合成树形结构以表示"部分-整体"的层次结构,组合使得用户对单个对象和组合对象的使用具有一致性。
-
常见的行为型设计模式包括:
- 策略模式(Strategy):允许在运行时选择算法的行为。
- 观察者模式(Observer):当一个对象状态改变时,所有依赖于它的对象都会得到通知并被自动更新。
- 命令模式(Command):将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化。
- 责任链模式(Chain of Responsibility):使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
- 状态模式(State):允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。
- 模板方法模式(Template Method):在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中实现。
单例模式 (Singleton)
https://zhuanlan.zhihu.com/p/37469260
- 保证一个类仅有一个实例,并提供一个访问它的全局访问点
- 相比于全局变量,单例模式可以延迟初始化,在使用前不会被创建,全局变量通常在启动时立即初始化
用法示例:
- 定义一个单例类 私有化它的构造函数
- 使用类的私有静态指针变量指向类的唯一实例;
- 使用一个公有的静态方法获取该实例。
懒汉版(Lazy Singleton)代码示例
cpp
// 单例实例在第一次被使用时才进行初始化
class Singleton
{
private:
static Singleton* instance;
private:
Singleton() {};
~Singleton() {};
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
public:
static Singleton* getInstance()
{
if(instance == NULL)
instance = new Singleton();
return instance;
}
};
// init static member
Singleton* Singleton::instance = NULL;
Meyers' Singleton 代码示例
cpp
// C++0x之后该实现是线程安全的
class Singleton
{
private:
Singleton() { };
~Singleton() { };
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
public:
static Singleton& getInstance()
{
static Singleton instance;
return instance;
}
};
饿汉版(Eager Singleton)代码示例
cpp
// 单例实例在程序运行时被立即执行初始化
class Singleton
{
private:
static Singleton instance;
private:
Singleton();
~Singleton();
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
public:
static Singleton& getInstance() {
return instance;
}
}
// initialize defaultly
Singleton Singleton::instance;
工厂方法模式(Factory Method)
- 封装创建逻辑(解耦、可重用、一致性和可维护性)
- 返回一个抽象类型的指针或接口,从而使得客户代码可以无需知道具体的产品类,只依赖于产品的接口或基类(多态)
- 相比于简单工厂模式(一个工厂方法,根据接受的参数不同,而创建不同的产品实例),工厂方法模式符合开闭原则,即无需修改 原有的工厂类和方法,只需增加新的产品类和对应的工厂类,(灵活性、可扩展性)
用法示例
- 定义抽象产品类Product
- 定义A产品类ProductA 继承自Product
- 定义B产品类ProductB 继承自Product
- 定义抽象工厂类Creator
- 定义A产品工厂类CreatorA
- 定义B产品工厂类CreatorB
- 创建X产品工厂类的实例 用于生成相应产品类的实例(均返回抽象类型Product的指针)
代码示例
cpp
#include <iostream>
#include <memory>
class Product {
public:
virtual void operation() = 0;
};
class ConcreteProductA : public Product {
public:
void operation() override {
std::cout << "Operation of ConcreteProductA" << std::endl;
}
};
class ConcreteProductB : public Product {
public:
void operation() override {
std::cout << "Operation of ConcreteProductB" << std::endl;
}
};
class Creator {
public:
virtual Product* factoryMethod() = 0;
};
class ConcreteCreatorA : public Creator {
public:
Product* factoryMethod() override {
return new ConcreteProductA();
}
};
class ConcreteCreatorB : public Creator {
public:
Product* factoryFactyoryMethod() override {
return new ConcreteProductB();
}
};
// 使用示例
int main() {
std::unique_ptr<Creator> creatorA(new ConcreteCreatorA());
std::unique_ptr<Product> productA(creatorA->factoryMethod());
productA->operation();
std::unique_ptr<Creator> creatorB(new ConcreteCreatorB());
std::unique_ptr<Product> productB(creatorB->factoryMethod());
productB->operation();
Creator* creater = new ConcreteCreatorX();
Product* product = creater->factoryMethod(); // 多态
product->operation(); // 多态
return 0;
}
适配器模式 (Adapter)
- 将不兼容的对象包装起来使其能够与其他类协同工作
- 将一个类的接口转换成另一个期望的接口
- 分为类适配器和对象适配器
- 类适配器使用继承(特别是多重继承)来实现适配:
- 优点:可以重写部分被适配者(Adaptee)的行为。
- 缺点:因为继承了被适配者,所以耦合度较高。
- 对象适配器使用组合来实现适配
- 优点:更加灵活,减少了类之间的耦合度。
- 缺点:需要额外的指针来访问被适配者。
- 类适配器使用继承(特别是多重继承)来实现适配:
用法示例
- 类适配器:公有继承新接口(虚基类),私有继承旧接口,重写新接口中的方法(调用旧接口方法)
- 对象适配器:公有继承新接口,拥有一个旧接口对象的引用,重写新接口中的方法(调用旧接口对象的成员方法)
代码示例
cpp
class OldRectangle {
public:
void draw() {
std::cout << "Old Rectangle draw method." << std::endl;
}
};
class NewShape {
public:
virtual void display() = 0;
virtual ~NewShape() {}
};
// 类适配器
class RectangleAdapter : public NewShape, private OldRectangle {
public:
void display() override {
// 调用 OldRectangle 的 draw 方法
draw();
}
};
// 对象适配器
class RectangleAdapter : public NewShape {
private:
OldRectangle* oldRectangle; // 持有一个对旧接口类的引用
public:
RectangleAdapter(OldRectangle* rectangle) : oldRectangle(rectangle) {}
void display() override {
// 调用 OldRectangle 的 draw 方法
oldRectangle->draw();
}
~RectangleAdapter() {
delete oldRectangle;
}
};
int main() {
OldRectangle* oldRectangle = new OldRectangle();
NewShape* rectangleAdapter = new RectangleAdapter(oldRectangle);
rectangleAdapter->display();
delete rectangleAdapter; // 注意:这将正确地释放适配器和旧的矩形对象
return 0;
}
外观模式 (Facade)
- 提供了一个统一的接口来访问子系统中的一组接口,来简化系统接口,减少用户对子系统的耦合
- 不符合开闭原则
用法示例
- 定义一个外观类,拥有其他类对象作为成员,其函数成员的实现为:一组对其他对象成员函数的调用
代码示例
cpp
class MultimediaSystemFacade {
private:
AudioPlayer audioPlayer;
VideoPlayer videoPlayer;
Broadcaster broadcaster;
public:
void playMultimedia() {
audioPlayer.playAudio();
videoPlayer.playVideo();
}
void sendMessage(const std::string& message) {
broadcaster.broadcastMessage(message);
}
};
代理模式(Proxy)
- 提供一个代替对象(代理对象)来控制对原对象的访问。通常用于延迟处理操作、控制访问、提供智能指引等功能
- 广泛应用于网络服务、内存中的大对象管理、安全控制等多种场景中
- 主要有三种类型:
- 虚拟代理:在需要时才创建开销很大的对象。
- 保护代理:控制对原始对象的访问,用于对象应有不同的访问权限时。
- 智能引用代理:当调用对象的特定方法时,执行一些附加操作,如计数对象引用次数、记录日志等。
用法示例
- 定义一个代理类,拥有被代理类对象作为成员,通过代理类调用被代理类的方法,从而在调用前添加额外的控制,实现延迟处理操作、控制访问、提供智能指引等
桥接模式(Bridge)
- 提供一个桥接结构,将抽象层和实现层解耦,从而简化了复杂系统的类结构
- 一维扩展用继承/组合,多维扩展(品牌与产品)用桥接
用法示例
- Abstraction (抽象类):定义抽象类的接口,它包含一个指向 Implementor 类型对象的引用。
- RefinedAbstraction (扩充抽象类):扩展 Abstraction 定义的接口。
- Implementor (实现类接口):定义实现类的接口,这些类具体实现基本操作,但在 Abstraction 中以抽象方式提供。
- ConcreteImplementor (具体实现类):Implementor 接口的具体实现。
例如:用于不同类型设备(如电视、无线投影仪等)的遥控器应用,每种设备都有不同的实现,但控制接口相似(开/关、调节音量等)
- 抽象 (Abstraction)
抽象部分由 RemoteControl 类及其扩展类 AdvancedRemoteControl 表示。这个抽象层定义了高层和通用的操作逻辑,如切换电源 (togglePower)、调节音量 (volumeUp, volumeDown) 以及静音操作 (mute)。- RemoteControl (基本遥控): 提供了基础的遥控功能。
- AdvancedRemoteControl (高级遥控): 在基本遥控的基础上增加了额外的功能,例如静音。
- 实现 (Implementor)
实现部分由 Device 接口及其具体实现类 TV 和 Radio 表示。这个层面处理关于设备的具体操作细节,如设备的开关状态和音量控制具体是如何执行的。- Device (设备接口): 定义了操作设备必须实现的方法,例如 enable(), disable(), getVolume(),
setVolume()。 - TV (电视): 实现了Device接口,提供了电视特有的操作方式。
- Radio (收音机): 同样实现了Device接口,按照收音机的方式执行操作。
- Device (设备接口): 定义了操作设备必须实现的方法,例如 enable(), disable(), getVolume(),
- 桥接连接
RemoteControl (抽象) 持有一个到 Device (实现) 的引用。这个引用允许抽象层通过实现层提供的接口与具体的设备进行交互,而不需要关心这些设备的具体实现细节。这就是所谓的"桥接",即抽象层和实现层之间通过组合而非继承来建立联系,从而使得两者可以独立地变化。
装饰器模式(包装模式)(Decorator)
- 动态地给一个对象添加一些额外的职责或功能,也是继承关系的一种代替方案(合成复用原则:组合大于继承),它通过组合而非继承增加功能,从而避免了由于继承引入的静态特性
用法示例
- 定义装饰器类,维持一个指向被装饰类对象的引用,实现被装饰类的接口,另外添加新的功能
模版方法模式(Template Method)
- 定义了一个操作中的算法的框架,将一些步骤的实现延迟到子类,允许子类在不改变算法结构的情况下重新定义算法的某些特定步骤
- 封装不变部分,扩展可变部分;提取公共代码,便于维护;行为由父类控制,子类实现
用法示例
- 定义抽象类,设置算法框架,实现固定部分,声明由子类实现的抽象操作。
- 定义继承自抽象类的具体类,实现抽象类中定义的抽象方法和钩子(hook)
代码示例
cpp
// 抽象类
class Beverage {
public:
// 模板方法,定义算法框架
void prepareRecipe() {
boilWater();
brew(); // 特定于子类的步骤
pourInCup();
addCondiments(); // 特定于子类的步骤
}
protected:
virtual void brew() = 0; // 由子类实现
virtual void addCondiments() = 0;// 由子类实现
void boilWater() {std::cout << "Boiling water" << std::endl;}
void pourInCup() {std::cout << "Pouring into cup" << std::endl;}
virtual ~Beverage() {}
};
// 具体类:咖啡
class Coffee : public Beverage {
protected:
void brew() override {std::cout << "Dripping Coffee through filter" << std::endl;}
void addCondiments() override {std::cout << "Adding Sugar and Milk" << std::endl;}
};
// 具体类:茶
class Tea : public Beverage {
protected:
void brew() override {std::cout << "Steeping the tea" << std::endl;}
void addCondiments() override {std::cout << "Adding Lemon" << std::endl;}
};
策略模式(Strategy)
- 定义了一组算法,他们可以以相同的接口共享。在根据不同的条件选择不同的行为时,可以使用此模式进行解耦,使代码更易于维护和扩展
- 使算法独立于使用他们的客户而独立变化。(在有多种算法相似的情况下,避免使用if...else所带来的复杂和难以维护)。
用法示例
- 定义抽象策略类,提供公共接口
- 定义继承自抽象策略类的具体策略类,提供具体算法实现
- 定义上下文类,其中维护一个对策略类对象的引用,用于设定策略,执行策略
观察者模式(Observer)
- 定义了对象之间的一对多依赖关系,当一个对象改变状态时,所有依赖于它的对象都会得到通知并自动更新
- 常用于实现分布式事件处理系统、在应用中实现跨系统的消息交换等场景
用法示例
- Subject(主题):也称为"被观察者",维护一份观察者列表,并提供用于增加或删除观察者的方法。
- Observer(观察者):为那些在主题状态发生改变时需获得通知的对象定义一个更新接口。
- ConcreteSubject(具体主题):状态变化时,向 Observer 发送通知,存储 Observer 对象关心的数据。
- ConcreteObserver(具体观察者):实现 Observer 的更新接口以使自身状态与主题的状态相协调。
代码示例
cpp
// Observer interface
class Observer {
public:
virtual void update(float price) = 0;
virtual ~Observer() {}
};
// Subject interface
class Subject {
public:
virtual void registerObserver(Observer* observer) = 0;
virtual void removeObserver(Observer* observer) = 0;
virtual void notifyObservers() = 0;
virtual ~Subject() {}
};
class Stock : public Subject {
private:
std::list<Observer*> observers;
float price;
public:
// Register an observer
void registerObserver(Observer* observer) override {observers.push_back(observer);}
// Remove an observer
void removeObserver(Observer* observer) override {observers.remove(observer);}
// Notify all registered observers
void notifyObservers() override {
for (auto& observer : observers) {
observer->update(price);
}
}
// Method to update price
void setPrice(float newPrice) {price = newPrice; notifyObservers();}
};
class PriceDisplay : public Observer {
private:
float price;
public:
void update(float newPrice) override {price = newPrice; display();}
void display() const {std::cout << "Current Stock Price: $" << price << std::endl;}
};
int main() {
Stock stock; // Create a Stock object which is the subject.
PriceDisplay display; // Create an observer.
stock.registerObserver(&display); // Register the observer with the subject.
stock.setPrice(150.0f); // Change the stock price, triggers notifications.
stock.setPrice(155.5f); // Change the stock price again.
stock.removeObserver(&display); // Unregister the observer.
stock.setPrice(160.0f); // No notification this time.
return 0;
}
责任链模式(Chain of Responsibility)
- 将请求的发送者和接收者解耦
- 多个对象都有机会处理请求,将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。
用法示例
- 定义处理者基类,拥有一个基类对象的引用(下一个处理者),提供处理请求的接口,提供设置下一个处理者的接口。
- 定义派生自基类的具体处理者类,实现处理请求的接口:处理它所负责的请求,如果可以处理就处理,不能处理就将请求转发给链上的下一个对象。
代码示例
cpp
#include <iostream>
#include <string>
// Handler
class Approver {
protected:
Approver* successor = nullptr;
public:
void setSuccessor(Approver* successor) {this->successor = successor;}
virtual void processRequest(int amount) = 0;
virtual ~Approver() {}
};
// ConcreteHandler1
class Manager : public Approver {
public:
void processRequest(int amount) override {
if (amount < 1000) {
std::cout << "Manager will approve $" << amount << std::endl;
} else if (successor) {
successor->processRequest(amount);
}
}
};
// ConcreteHandler2
class Director : public Approver {
public:
void processRequest(int amount) override {
if (amount < 5000) {
std::cout << "Director will approve $" << amount << std::endl;
} else if (successor) {
successor->processRequest(amount);
}
}
};
// ConcreteHandler3
class CEO : public Approver {
public:
void processRequest(int amount) override {
if (amount < 20000) {
std::cout << "CEO will approve $" << amount << std::endl;
} else {
std::cout << "Request $" << amount << " needs further meeting!" << std::endl;
}
}
};
int main() {
Manager manager;
Director director;
CEO ceo;
// Set up the chain
manager.setSuccessor(&director);
director.setSuccessor(&ceo);
// Various requests
manager.processRequest(500); // Manager handles this request
manager.processRequest(1500); // Director handles this request
manager.processRequest(7000); // CEO handles this request
manager.processRequest(50000); // Needs further meeting
return 0;
}