目录
- 工厂模式
- 单例模式
- 适配器模式
- 外观模式
- 代理模式
- 桥接模式
- 模板方法模式
- 策略模式
- 观察者模式
- 责任链模式
c++常用的设计模式包括单例模式、工厂模式、抽象工厂模式、适配器模式、装饰者模式、代理模式、外观模式、桥接模式、组合模式、享元模式、观察者模式和命令模式等。使用设计模式的好处:提高代码的可读性和可维护性;将常见的设计问题隔离程序的业务逻辑;重用已有的实现;消除重复代码;消除手动调整代码以达到正确逻辑的所有痛苦。
工厂模式
C++工厂模式是一种模式,它是一种创建对象的有效方法。它允许我们使用一个类来负责创建实现特定接口的不同具体类的实例,而无需明确指定该实例的具体类。通过抽象出一个工厂类来负责每个子类的实例化,使得代码的可维护性大大增加。这种模式也使得添加新类型的实例变得容易,只要扩展工厂类即可。
#include<iostream>
using namespace std;
// A 'Product' class
class Product
{
public:
virtual void show() =;
};
// A 'ConcreteProduct' class
class ConcreteProduct : public Product
{
public:
void show() { cout << "I am a ConcreteProduct object" << endl; }
};
// A 'Creator' abstract class
class Creator
{
public:
virtual Product* createProduct() =;
};
// A 'ConcreteCreator' class
class ConcreteCreator : public Creator
{
public:
Product* createProduct()
{
return new ConcreteProduct();
}
};
// Client
int main()
{
Creator* creator = new ConcreteCreator();
Product* product = creator->createProduct();
product->show();
return;
}
单例模式
单例 Singleton 是设计模式的一种,其特点是只提供唯一一个类的实例,具有全局变量的特点,在任何位置都可以通过接口获取到那个唯一实例。
class Singleton
{
private:
static Singleton* instance;
Singleton() { }
public:
static Singleton* getInstance() {
if(instance == nullptr)
instance = new Singleton();
return instance;
}
};
Singleton* Singleton::instance = nullptr;
以上只是一种通用实现教学版,即懒汉版(Lazy Singleton):单例实例在第一次被使用时才进行初始化,这叫做延迟初始化,然而可能存在内存泄漏的风险,且这个代码在单线程环境下是正确无误的,但是当拿到多线程环境下时这份代码就会出现race condition。
C++11规定了local static在多线程条件下的初始化行为,要求编译器保证了内部静态变量的线程安全性。在C++11标准下,《Effective C++》提出了一种更优雅的单例模式实现,使用函数内的 local static 对象。这样,只有当第一次访问getInstance()方法时才创建实例。这种方法也被称为Meyers' Singleton。C++0x之后该实现是线程安全的,C++0x之前仍需加锁。
class Singleton
{
private:
Singleton() { };
~Singleton() { };
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
public:
static Singleton& getInstance()
{
static Singleton instance;
return instance;
}
};
适配器模式
C++ 适配器模式是一种结构型设计模式,它允许现有的类在不修改其内部结构的情况下在其他类中可用。它使用适配器来将不兼容的接口转换成用于目标类的接口。适配器模式使客户端能够调用他们正在使用的接口,而实际上正在使用另一个接口,这个新接口已经与客户端的要求匹配。
#include <iostream>
using namespace std;
// 定义接口
class Target
{
virtual void request() =;
};
// 创建一个需要被适配的类
class Adaptee
{
void specificRequest();
};
// 创建一个适配器
class Adapter : public Target
{
Adaptee *adaptee;
public:
Adapter(Adaptee *adaptee) { this->adaptee = adaptee; }
void request()
{
// 执行specificRequest方法
adaptee->specificRequest();
}
};
int main()
{
Adaptee *adaptee = new Adaptee();
Target *target = new Adapter(adaptee);
target->request();
return;
}
外观模式
在C++中,外观模式是一种使用来简化系统接口的模式。它由一个“外观”类定义,这个类知道要包装的一系列子系统类。客户可以通过外观类直接访问子系统中的功能而不必了解内部细节。这样会降低时间和精力,可以减少客户端访问子系统的数量,所以它是一种简易的方法,用于整合子系统的接口。
Façade模式
class ComputerFacade
{
private:
CPU *cpu;
Memory *mem;
HardDrive *hd;
public:
ComputerFacade()
{
cpu = new CPU();
mem = new Memory();
hd = new HardDrive();
}
~ComputerFacade()
{
delete cpu;
delete mem;
delete hd;
}
void startComputer()
{
cpu->freeze();
mem->load(BOOT_ADDRESS, hd->read(BOOT_SECTOR, SECTOR_SIZE));
cpu->execute();
}
};
代理模式
代理模式(Proxy Pattern)是一种结构型设计模式,它为另外一个对象提供一个替代或占位符。当客户无法直接访问另外一个对象时,代理就可以担任中间人的角色,这样,客户就可以通过代理对象访问那个对象了。C++ 可以使用代理模式来实现对象的访问控制,可以使用该模式来管理对象的生命周期,也可以使用该模式来控制对象的访问,以及在跨平台上实现方法调用。
/**
* @file proxy.cpp
* @brief 代理模式实现示例
*
* 代理模式用于在不直接访问一个对象的情况下提供访问方式。
* 它通常由真实对象和代理对象代表,其中真实对象处理实际工作,而代理对象只是
* 提供其接口,本文将使用 C++ 代码来实现代理模式。
*/
#include <iostream>
// 真实对象基类
class RealObject
{
public:
virtual void doSomething() =;
};
// 真实对象实现类
class RealObjectImpl : public RealObject
{
public:
virtual void doSomething()
{
std::cout << "Doing something in RealObjectImpl" << std::endl;
}
};
// 代理对象基类,保存一个指向 RealObjectImpl
// 对象的指针
class ProxyObject
{
private:
RealObject* m_realObject;
public:
ProxyObject() : m_realObject(nullptr)
{
m_realObject = new RealObjectImpl();
}
~ProxyObject()
{
delete m_realObject;
m_realObject = nullptr;
}
// 调用真实对象的 doSomething()
void doSomething()
{
if(m_realObject != nullptr)
{
m_realObject->doSomething();
}
}
};
int main()
{
ProxyObject proxyObject;
proxyObject.doSomething();
return;
}
桥接模式
C++桥接模式是一种设计模式,它把抽象和实现分离开来,以便两者独立地变化。此模式在不同的编程语言之间创建了一个“桥”,支持平台无关性,以实现代码重用。它通常由抽象类处理,以及一个“管理类”,该类将实现类注入抽象类中。
// Bridge Pattern – C++
#include <iostream>
// Abstract class having the implementation for the interface
class Shape
{
public:
virtual void draw() =;
virtual ~Shape(){}
};
// Concrete class
class Rectangle : public Shape
{
public:
void draw() override
{
std::cout << "Drawing a rectangle." << std::endl;
}
};
// Concrete class
class Circle : public Shape
{
public:
void draw() override
{
std::cout << "Drawing a circle." << std::endl;
}
};
// Bridge between implementation and interface
class DrawingAPI
{
public:
virtual void drawCircle(double x, double y, double radius) =;
virtual void drawRectangle(double x, double y, double width,
double height) =;
virtual ~DrawingAPI() {}
};
// Concrete bridge
class DrawingAPI : public DrawingAPI
{
public:
void drawCircle(double x, double y, double radius) override
{
std::cout << "API.circle at " << x << ':' << y
<< ' ' << radius << std::endl;
}
void drawRectangle(double x, double y, double width,
double height) override
{
std::cout << "API.rectangle at " << x << ':' << y
<< ' ' << width << 'x' << height << std::endl;
}
};
// Concrete bridge
class DrawingAPI : public DrawingAPI
{
public:
void drawCircle(double x, double y, double radius) override
{
std::cout << "API.circle at " << x << ':' << y
<< ' ' << radius << std::endl;
}
void drawRectangle(double x, double y, double width,
double height) override
{
std::cout << "API.rectangle at " << x << ':' << y
<< ' ' << width << 'x' << height << std::endl;
}
};
// Shape implementation using bridge
class Shape : public Shape
{
private:
DrawingAPI* m_drawingAPI;
public:
Shape(DrawingAPI* drawingAPI)
: m_drawingAPI(drawingAPI)
{ }
void draw() override
{
m_drawingAPI->drawCircle(.0, 2.0, 3.0);
}
};
// Another shape using same bridge
class Shape : public Shape
{
private:
DrawingAPI* m_drawingAPI;
public:
Shape(DrawingAPI* drawingAPI)
: m_drawingAPI(drawingAPI)
{ }
void draw() override
{
m_drawingAPI->drawRectangle(.0, 5.0, 6.0, 7.0);
}
};
// Client
int main()
{
DrawingAPI* drawingAPI = new DrawingAPI();
Shape* shapes[] =
{
new Shape(drawingAPI),
new Shape(drawingAPI)
};
for (Shape* shape : shapes)
shape->draw();
return;
}
模板方法模式
模板方法模式是指定义一个操作中算法的框架,而将算法的一些步骤延迟到子类中实现。模板方法模式使得子类可以不改变算法的结构即可重定义算法的某些特定步骤。 它是一种行为设计模式,它定义一个算法的模板,将一些计算步骤推迟到子类中。 在C++中,模板方法通常采用继承机制实现,在基类中定义算法的框架,在子类中实现算法的某些步骤。
//Base class
template <class T>
class Base
{
public:
void templateMethod()
{
step();
step();
step();
step();
}
virtual void step() = 0;
virtual void step() = 0;
virtual void step() = 0;
virtual void step() = 0;
};
//Derived class
template <class T>
class Derived : public Base<T>
{
public:
Derived(T data):m_data(data) {}
virtual void step()
{
std::cout<<"Step with the data: "<< m_data <<std::endl;
}
virtual void step()
{
std::cout<<"Step with the data: "<< m_data <<std::endl;
}
virtual void step()
{
std::cout<<"Step with the data: "<< m_data <<std::endl;
}
virtual void step()
{
std::cout<<"Step with the data: "<< m_data <<std::endl;
}
private:
T m_data;
};
//Client
int main()
{
Base<int> *b = new Derived<int>();
b->templateMethod();
delete b;
return;
}
策略模式
是一种行为设计模式,它定义了一组算法,他们可以以相同的接口共享。这种模式使用场景最多的就是在根据不同的条件选择不同的行为时,可以使用此模式进行解耦,使得你的代码更加易于维护和扩展,当然也要看开发场景。
#include <iostream>
using namespace std;
// 抽象策略类
class Strategy
{
public:
virtual void AlgorithmInterface() =; // 策略接口
};
// 具体策略类A
class ConcreteStrategyA : public Strategy
{
public:
void AlgorithmInterface()
{
cout<<"using algoritm A"<<endl;
}
};
// 具体策略类B
class ConcreteStrategyB : public Strategy
{
public:
void AlgorithmInterface()
{
cout<<"using algoritm B"<<endl;
}
};
// 环境类Context
class Context
{
private:
Strategy * strategy; // 私有策略类指针
public:
Context(Strategy * pStrategy)
{
this->strategy = pStrategy;
}
void DoAction()
{
strategy->AlgorithmInterface(); // 使用策略类
}
};
// 使用
int main()
{
Context contextA(new ConcreteStrategyA); // 设定策略A
contextA.DoAction();
Context contextB(new ConcreteStrategyB); // 设定策略B
contextB.DoAction();
return;
}
观察者模式
观察者模式是一种行为型设计模式,它允许多个“观察者”被通知某些情况的变化。被观察的对象(通常称为被观察者)将不断发出关于自身状态的更新通知,而这些观察者则侦听此变化并执行相应的操作。在C++中,观察者模式可以使用虚函数,继承,容器和模板类来实现。
#include <iostream>
#include <list>
// 抽象被观察者的接口
class Subject {
public:
// 注册观察者
virtual void Attach(Observer* pObserver) =;
// 移除观察者
virtual void Detach(Observer* pObserver) =;
// 通知所有观察者
virtual void Notify() =;
virtual ~Subject(){}
};
// 抽象观察者的接口
class Observer {
public:
// 响应被观察者的通知
virtual void Update() =;
virtual ~Observer(){}
};
// 被观察者
class ConcreteSubject : public Subject {
public:
void Attach(Observer* pObserver) override {
m_observers.push_back(pObserver);
}
void Detach(Observer* pObserver) override {
m_observers.remove(pObserver);
}
void Notify() override {
for (auto pObserver : m_observers)
pObserver->Update();
}
private:
std::list<Observer*> m_observers;
};
// 具体观察者
class ConcreteObserver : public Observer {
public:
void Update() override {
std::cout << "ConcreteObserver Update" << std::endl;
}
};
class ConcreteObserver : public Observer {
public:
void Update() override {
std::cout << "ConcreteObserver Update" << std::endl;
}
};
int main() {
ConcreteSubject subject;
ConcreteObserver observer1;
ConcreteObserver observer2;
subject.Attach(&observer);
subject.Attach(&observer);
subject.Notify();
return;
}
责任链模式
责任链模式(Chain of Responsibility Pattern)是一种行为设计模式,它定义了请求的处理者对象之间的关系,并使多个处理者有机会处理该请求。当发出一个请求时,请求将沿着链条一直传递,直到链上的某一个处理者决定请求的处理方式。
#include<iostream>
using namespace std;
//定义抽象类Handler
class Handler
{
protected:
Handler* successor; // 定义后继对象
public:
Handler() {
successor = NULL;
}
void SetSuccessor(Handler* suc) {
successor = suc;
}
virtual void HandleRequest() =; // 处理请求的抽象方法
};
//实现抽象类Handler
class ConcreteHandler : public Handler
{
public:
void HandleRequest() {
if (successor != NULL) {
cout << "ConcreteHandler 放过请求" << endl;
successor->HandleRequest();
}
else
{
cout << "ConcreteHandler 处理请求"<<endl;
}
}
};
class ConcreteHandler : public Handler
{
public:
void HandleRequest() {
if (successor != NULL) {
cout << "ConcreteHandler 放过请求" << endl;
successor->HandleRequest();
}
else
{
cout << "ConcreteHandler 处理请求"<<endl;
}
}
};
//Client四
int main(int argc, char* argv[])
{
ConcreteHandler* handler1 = new ConcreteHandler1();
ConcreteHandler* handler2 = new ConcreteHandler2();
handler->SetSuccessor(handler2);
handler->HandleRequest();
return;
}