设计模式
单例模式
单例模式是一种设计模式,它确保类在应用程序的生命周期内只有一个实例,并提供了一种全局访问该实例的方式。单例模式通常在需要确保只有一个对象负责特定任务或资源管理的情况下使用。
单例模式通常包含以下几个要素:
-
私有构造函数:单例类的构造函数被声明为私有,这样外部就无法通过实例化新对象来创建类的多个实例。
-
静态成员变量:单例类通常会包含一个静态成员变量,用于存储该类的唯一实例。
-
静态方法:单例类通常会包含一个静态方法,用于获取类的唯一实例。这个方法通常会在第一次调用时创建实例,并在后续调用时返回相同的实例。
使用懒汉式实现
#include <iostream>
using namespace std;
class Singleton{
private:
Singleton() {};
~Singleton() {};
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
private:
static Singleton* m_instance;
public:
static Singleton* getInstance() {
if (m_instance == nullptr) {
m_instance = new Singleton();
}
return m_instance;
}
void show() {
printf("hhh!\n");
}
};
Singleton* Singleton::m_instance = nullptr;
int main() {
Singleton::getInstance()->show();
return 0;
}
这个示例中的Singleton类保证了在应用程序的生命周期内只有一个实例存在,并且通过getInstance方法可以全局访问该实例。
使用饿汉式实现
#include <iostream>
class Singleton {
private:
Singleton(){};
static Singleton* m_instance;
public:
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static Singleton* getInstance() {
return m_instance;
}
void show() {
std::cout << "do something" << std::endl;
}
};
// 直接初始化
Singleton* Singleton::m_instance = new Singleton();
int main() {
Singleton::getInstance()->show();
Singleton* a = Singleton::getInstance();
Singleton* b = Singleton::getInstance();
std::cout << "a == b: " << (a == b) << std::endl;
return 0;
}
使用std::call_once实现线程安全的单例模式
使用 std::call_once
函数可以简洁地实现线程安全的单例模式。std::call_once
保证了函数仅在第一次调用时执行,并且可以在多线程环境下安全地执行一次初始化。
#include <iostream>
#include <mutex>
class Singleton{
private:
Singleton() {}
static Singleton* m_instance;
static std::once_flag flag;
public:
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static Singleton* getInstance() {
std::call_once(flag, [](){
m_instance = new Singleton();
});
return m_instance;
}
void show() {
std::cout << "do something" << std::endl;
}
};
Singleton* Singleton::m_instance = nullptr;
std::once_flag Singleton::flag;
int main() {
Singleton::getInstance()->show();
Singleton* a = Singleton::getInstance();
Singleton* b = Singleton::getInstance();
std::cout << "a == b: " << (a == b) << std::endl;
return 0;
}
装饰器模式
装饰器模式是一种结构型设计模式,它允许向现有对象动态地添加新功能,同时不改变其结构。这种模式通过将对象放入包装器中,然后用一个或多个装饰器对象来包装原始对象,以提供额外的功能。装饰器模式是继承的一种灵活替代方案,它可以在不修改现有代码的情况下增加功能。
装饰器模式通常包含以下几个要素:
-
组件接口(Component):定义了被装饰对象和装饰器共同实现的接口或抽象类。
-
具体组件(Concrete Component):实现了组件接口,是被装饰的原始对象。
-
装饰器(Decorator):继承了组件接口,并持有一个指向被装饰对象的引用。装饰器可以通过在调用被装饰对象之前或之后添加额外的行为来扩展组件的功能。
-
具体装饰器(Concrete Decorator):扩展了装饰器类,实现了具体的装饰逻辑。它可以添加一些额外的功能到被装饰对象上。
以下是一个简单的装饰器模式的示例:
#include <iostream>
#include <memory>
// 抽象基类
class Component {
public:
virtual void operation() = 0;
virtual ~Component() = default;
};
// 具体组件
class ConcreteComponent: public Component {
void operation() override {
std::cout << "ConcreteComponent operation!" << std::endl;
}
};
// 装饰器基类
class Decorator: public Component {
protected:
std::shared_ptr<Component> component_;
public:
explicit Decorator(std::shared_ptr<Component> component): component_(std::move(component)) {}
void operation() override {
if (component_) {
component_->operation();
}
}
};
// 具体装饰器
class ConcreteDecoratorA: public Decorator {
public:
explicit ConcreteDecoratorA(std::shared_ptr<Component> component): Decorator(std::move(component)) {}
void operation() override{
Decorator::operation();
addBehavior();
}
void addBehavior() {
std::cout << "ConcreteDecoratorA added behavior" << std::endl;
}
};
class ConcreteDecoratorB: public Decorator {
public:
explicit ConcreteDecoratorB(std::shared_ptr<Component> component): Decorator(std::move(component)) {}
void operation() override {
Decorator::operation();
addBehavior();
}
void addBehavior() {
std::cout << "ConcreteDecoratorB added behavior" << std::endl;
}
};
int main() {
std::shared_ptr<Component> component = std::make_shared<ConcreteComponent>();
std::shared_ptr<ConcreteDecoratorA> cda = std::make_shared<ConcreteDecoratorA>(component);
std::shared_ptr<ConcreteDecoratorB> cdb = std::make_shared<ConcreteDecoratorB>(component);
component->operation();
cda->operation();
cdb->operation();
}
工厂模式
工厂模式是一种创建型设计模式,它提供了一种将对象的创建与使用分离的方法。工厂模式通过将对象的实例化过程委托给一个单独的工厂类来创建对象,而不是在客户端代码中直接实例化对象。这样可以使客户端代码与具体类的实现解耦,并且使得系统更加灵活,易于扩展和维护。
工厂模式通常包括三种变体:
-
简单工厂模式(Simple Factory Pattern):简单工厂模式是工厂模式的最简单形式,它通过一个工厂类来创建对象,根据传入的参数不同返回不同类的实例。这种模式适用于创建对象的逻辑相对简单的情况。
-
工厂方法模式(Factory Method Pattern):工厂方法模式定义了一个创建对象的接口,但是将具体的实现延迟到子类中。这样每个子类都可以根据需要创建自己特定类型的对象。工厂方法模式通过面向对象的多态性实现,提供了一种更加灵活的对象创建方式。
-
抽象工厂模式(Abstract Factory Pattern):抽象工厂模式提供了一种创建一系列相关或依赖对象的方法,而无需指定它们具体的类。它通过引入抽象工厂接口和具体工厂实现类的方式,将一组相关的对象创建集中在一起,使得客户端代码可以在不同的工厂实现之间切换,而不必修改其余代码。
工厂模式的主要优点包括:
- 封装性:将对象的创建过程封装在工厂类中,客户端无需关心对象的创建细节。
- 灵活性:可以通过修改工厂类来改变所创建的具体对象类型,而无需修改客户端代码。
- 可扩展性:添加新的产品类型只需增加新的工厂类或者修改现有的工厂类,不会对现有代码造成影响。
- 解耦性:客户端代码与具体产品类之间解耦,降低了代码的依赖性。
总的来说,工厂模式是一种重要的设计模式,在实际开发中被广泛应用,可以帮助我们更好地组织代码结构,提高代码的灵活性和可维护性。
简单工厂模式
#include <iostream>
// 抽象产品类
class Product {
public:
virtual void operation() = 0;
virtual ~Product() {}
};
// 具体产品A
class ConcreteProductA: public Product {
public:
void operation() override {
std::cout << "ConcreteProductA operation" << std::endl;
}
};
// 具体产品B
class ConcreteProductB: public Product {
public:
void operation() override {
std::cout << "ConcreteProductB operation" << std::endl;
}
};
class SimpleFactory {
public:
static Product* createProduct(char ch) {
switch (ch) {
case 'A':
return new ConcreteProductA();
break;
case 'B':
return new ConcreteProductB();
break;
default:
return nullptr;
break;
}
}
};
int main() {
Product* productA = SimpleFactory::createProduct('A');
if (productA) {
productA->operation();
delete productA;
}
Product* productB = SimpleFactory::createProduct('B');
if (productB) {
productB->operation();
delete productB;
}
return 0;
}
工厂方法模式
#include <algorithm>
#include <iostream>
#include <memory>
class Product {
public:
virtual void operation() = 0;
virtual ~Product() {}
};
class ConcreteProductA: public Product {
public:
void operation() override {
std::cout << "ConcreteProductA operation" << std::endl;
}
};
class ConcreteProductB: public Product {
public:
void operation() override {
std::cout << "ConcreteProductB operation" << std::endl;
}
};
// 抽象工厂类
class Factory{
public:
virtual std::shared_ptr<Product> createProduct() = 0;
virtual ~Factory() = default;
};
// 具体工厂类
class ConcreteFactoryA: public Factory {
public:
std::shared_ptr<Product> createProduct() override {
return std::make_shared<ConcreteProductA>();
}
};
class ConcreteFactoryB: public Factory {
public:
std::shared_ptr<Product> createProduct() override {
return std::make_shared<ConcreteProductB>();
}
};
int main() {
std::unique_ptr<Factory> factoryA = std::make_unique<ConcreteFactoryA>();
std::shared_ptr<Product> productA = factoryA->createProduct();
productA->operation();
std::unique_ptr<Factory> factoryB = std::make_unique<ConcreteFactoryB>();
std::shared_ptr<Product> productB = factoryB->createProduct();
productB->operation();
return 0;
}
抽象工厂模式
#include <iostream>
#include <memory>
// 抽象A产品
class AbstractProductA {
public:
virtual void operationA() = 0;
virtual ~AbstractProductA() = default;
};
// 具体产品A1
class ConcreteProductA1: public AbstractProductA {
public:
void operationA() override {
std::cout << "ConcreteProductA1 operation" << std::endl;
}
};
// 具体产品A2
class ConcreteProductA2: public AbstractProductA {
public:
void operationA() override {
std::cout << "ConcreteProductA2 operation" << std::endl;
}
};
// 抽象产品B
class AbstractProductB {
public:
virtual void operationB() = 0;
virtual ~AbstractProductB() = default;
};
// 具体产品B1
class ConcreteProductB1: public AbstractProductB {
public:
void operationB() override {
std::cout << "ConcreteProductB1 operation" << std::endl;
}
};
// 具体产品B2
class ConcreteProductB2: public AbstractProductB {
public:
void operationB() override {
std::cout << "ConcreteProductB2 operation" << std::endl;
}
};
// 抽象工厂
class AbstractFactory {
public:
virtual std::shared_ptr<AbstractProductA> createProductA() = 0;
virtual std::shared_ptr<AbstractProductB> createProductB() = 0;
virtual ~AbstractFactory() = default;
};
// 具体工厂A
class ConcreteFactoryA: public AbstractFactory {
public:
std::shared_ptr<AbstractProductA> createProductA() override {
return std::make_shared<ConcreteProductA1>();
}
std::shared_ptr<AbstractProductB> createProductB() override {
return std::make_shared<ConcreteProductB1>();
}
};
// 具体工厂B
class ConcreteFactoryB: public AbstractFactory {
public:
std::shared_ptr<AbstractProductA> createProductA() override {
return std::make_shared<ConcreteProductA2>();
}
std::shared_ptr<AbstractProductB> createProductB() override {
return std::make_shared<ConcreteProductB2>();
}
};
int main() {
std::unique_ptr<AbstractFactory> factoryA = std::make_unique<ConcreteFactoryA>();
auto productA1 = factoryA->createProductA();
auto productB1 = factoryA->createProductB();
productA1->operationA();
productB1->operationB();
std::unique_ptr<AbstractFactory> factoryB = std::make_unique<ConcreteFactoryB>();
auto productA2 = factoryB->createProductA();
auto productB2 = factoryB->createProductB();
productA2->operationA();
productB2->operationB();
return 0;
}
观察者模式
观察者模式是一种常用的软件设计模式,它属于行为型模式的一种。在观察者模式中,存在一个称为"Subject"的主题对象,以及多个称为"Observers"的观察者对象。这些观察者对象通过订阅主题对象,当主题对象的状态发生变化时,会得到通知并做出相应的更新。
以下是观察者模式的主要角色及其功能:
-
Subject(主题):
- 主题对象是被观察的对象,它维护着一系列观察者对象,并提供了注册、删除和通知观察者的方法。
- 当主题对象的状态发生改变时,会通知所有注册的观察者对象。
-
Observer(观察者):
- 观察者对象订阅了主题对象,以便在主题对象状态变化时接收通知。
- 观察者对象需要实现一个更新方法,以便在接收到通知时执行相应的操作。
观察者模式的核心思想在于将主题对象与观察者对象解耦,使得它们可以独立地进行修改和扩展。这种模式通常用于实现事件处理系统、GUI框架、消息队列等场景,其中一个对象的状态变化需要通知其他对象做出相应的反应。
在具体的实现中,可以通过使用回调函数、事件委托、消息队列等机制来实现观察者模式。例如,在面向对象的编程语言中,可以定义主题对象接口和观察者接口,然后让具体的主题类和观察者类分别实现这些接口。
以下是观察者模式的一个实现:
#include <iostream>
#include <vector>
#include <algorithm>
// 抽象观察者
class Observer {
public:
virtual void update() = 0;
};
// 具体观察者A
class ConcreteObserverA: public Observer {
public:
void update() override {
std::cout << "ConcreteObserverA received update" << std::endl;
}
};
// 具体观察者B
class ConcreteObserverB: public Observer {
public:
void update() override {
std::cout << "ConcreteObserverB received update" << std::endl;
}
};
// 主题
class Subject {
private:
std::vector<Observer*> observers;
public:
// 注册观察者
void attach(Observer* observer) {
observers.push_back(observer);
}
// 移除观察者
void detach(Observer* observer) {
observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
}
// 通知观察者
void notify() {
for (auto observer: observers) {
observer->update();
}
}
};
int main() {
// 创建具体的观察者
ConcreteObserverA a;
ConcreteObserverB b;
// 创建主题
Subject subject;
// 注册观察者
subject.attach(&a);
subject.attach(&b);
// 通知观察者
subject.notify();
// 移除观察者
subject.detach(&a);
// 通知观察者
subject.notify();
return 0;
}
这个示例中,我们首先定义了一个抽象的观察者类 Observer
,它包含了一个纯虚函数 update()
用于在具体观察者中实现。
然后,我们创建了两个具体的观察者类 ConcreteObserverA
和 ConcreteObserverB
,它们分别实现了 update()
函数。
接着,我们定义了主题类 Subject
,其中包含了一个 std::vector
来存储注册的观察者。Subject
类提供了 attach()
、detach()
和 notify()
方法,用于注册、移除和通知观察者。
在 main()
函数中,我们创建了具体的观察者对象,并将它们注册到主题对象中。然后调用 notify()
方法通知所有的观察者。最后,我们移除了观察者A,并再次通知观察者。
策略模式
策略模式(Strategy Pattern)是一种行为设计模式,它允许在运行时选择算法的行为。它定义了一族算法,并且将每一个算法封装到具有共同接口的独立类中,使得它们可以互相替换。这种模式使得算法的变化独立于使用算法的客户端。
策略模式包含三个主要角色:
-
Context(上下文):它是使用特定策略的对象。上下文对象通过与策略接口的交互,委托执行算法的具体实现。通常,上下文类会持有一个策略对象的引用,并在运行时决定使用哪个具体策略。
-
Strategy(策略):它是一个接口或抽象类,定义了一个算法族的共同接口。所有的具体策略类都实现了这个接口,从而保证了它们可以相互替换。策略接口中通常包含一个或多个方法,表示不同的算法。
-
ConcreteStrategy(具体策略):它是策略接口的具体实现类。每个具体策略类代表了一种具体的算法实现。在运行时,上下文对象可以选择使用其中一个具体策略来完成特定的任务。
策略模式的核心思想在于将算法的实现从客户端代码中解耦,使得客户端可以独立于具体的算法选择。它提供了一种简洁的方式来处理多种算法变体的情况,同时也提高了代码的可维护性和可扩展性。常见的应用场景包括:排序算法、数据结构选择、文件压缩等。
下面是一个使用 C++ 实现策略模式的简单示例:
#include <iostream>
// 策略接口
class Strategy {
public:
virtual void execute() = 0;
virtual ~Strategy() = default;
};
// 具体策略A
class ConcreteStrategyA: public Strategy {
public:
void execute() override {
std::cout << "ConcreteStrategyA executed!" << std::endl;
}
};
// 具体策略B
class ConcreteStrategyB: public Strategy {
public:
void execute() override {
std::cout << "ConcreteStrategyB executed!" << std::endl;
}
};
class Context {
private:
Strategy* strategy;
public:
Context(Strategy* strategy): strategy(strategy) {}
void setStrategy(Strategy* strategy) {
this->strategy = strategy;
}
void executeStrategy() {
strategy->execute();
}
};
int main() {
ConcreteStrategyA a;
ConcreteStrategyB b;
Context context(&a);
context.executeStrategy();
context.setStrategy(&b);
context.executeStrategy();
return 0;
}