设计模式
1. 工厂模式 - 工厂的魔力
工厂模式属于创建者模式,提供了一种创建对象的最佳方式。创建型模式关注对象的创建过程,在软件开发中应用非常广泛。创建型模式描述如何将对象的创建和使用分离,让用户在使用对象过程中无须关心对象的创建细节,从而降低系统耦合度,并且让系统易于修改和扩展。
工厂模式的实现方式有简单工厂模式、工厂方法模式、抽象工厂模式,每个实现方式都存在优和劣。
简单工厂模式与工厂模式的结构组成是:
- 工厂类:工厂模式的核心类,会定义一个用于创建指定的具体实例对象的接口。(可分为抽象工厂和具体工厂)
- 抽象产品类:是具体产品类的继承的父类或实现的接口。
- 具体产品类:工厂类所创建的对象就是此具体产品实例。
以汽车厂为例:
Cars为汽车的抽象类(基类),接口函数为Show(),用于显示文本。
Benzi、Audi、Bmw为具体汽车品牌的类,它们都继承于Cars抽象类。
// 汽车抽象类
class Cars
{
public:
virtual ~Cars() {}
virtual void Show() = 0;
};
// 奔驰 - 具体产品的实现方法
class Benzi: public Cars
{
public:
void Show()
{
std::cout << "我是Benzi" << std::endl;
}
};
// 奥迪
class Audi: public Cars
{
public:
void Show()
{
std::cout << "我是Audi" << std::endl;
}
};
CarsFactory为工厂类,类里实现根据汽车类型创建对应产品对象的CreateCars(CARS_TYPE type)函数。
enum CARS_TYPE
{
BENZI,
AUDI
};
// 总车厂
class CarsFactory
{
public:
// 根据鞋子类型创建对应的鞋子对象
Cars *CreateCars(CARS_TYPE type)
{
switch (type)
{
case BENZI:
return new Benzi();
break;
case AUDI:
return new Audi();
break;
default:
return NULL;
break;
}
}
};
main函数,先是构造了工厂对象,然后创建指定类型的具体产品对象,然后输出对应文本。因为采用的是new
的方式创建了对象,用完了要通过delete
释放资源资源。
int main()
{
// 构造工厂对象
CarsFactory carsFactory;
// 从工厂对象创建benzi对象
Cars *pBenzi = carsFactory.CreateCars(BENZI);
if (pBenzi != NULL)
{
pBenzi->Show();
// 释放资源
delete pBenzi;
pBenzi = NULL;
}
// 从工厂对象创建audi对象
Cars *pAudi = carsFactory.CreateCars(AUDI);
if (pAudi != NULL)
{
pAudi ->Show();
// 释放资源
delete pAudi ;
pAudi = NULL;
}
return 0;
}
简单工厂模式的优点在于:
- 工厂类提供创建具体产品的方法,并包含一定判断逻辑,客户不必参与产品的创建过程;
- 客户只需要知道对应产品的参数即可,参数一般简单好记,如数字、字符或者字符串等。
2. 工厂方法模式 - 多样化的工厂
简单工厂模式存在最大的问题是违背了“开闭原则”,每当增加新的产品时,需要修改工厂类的逻辑。为了规避这种不足,同时很好的利用简单工厂模式的优点,这里介绍工厂方法模式。
工厂方法模式:定义一个用于创建对象的接口,但是让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。
#include <iostream>
#include <string>
// 产品基类
class Product {
public:
virtual void use() = 0;
};
// 具体产品类 A
class ConcreteProductA : public Product {
public:
void use() override {
std::cout << "Using ConcreteProductA" << std::endl;
}
};
// 具体产品类 B
class ConcreteProductB : public Product {
public:
void use() override {
std::cout << "Using ConcreteProductB" << std::endl;
}
};
// 工厂基类
class Factory {
public:
virtual Product* createProduct() = 0;
};
// 具体工厂类 A
class ConcreteFactoryA : public Factory {
public:
Product* createProduct() override {
return new ConcreteProductA();
}
};
// 具体工厂类 B
class ConcreteFactoryB : public Factory {
public:
Product* createProduct() override {
return new ConcreteProductB();
}
};
int main() {
// 使用具体工厂 A 创建产品 A
Factory* factoryA = new ConcreteFactoryA();
Product* productA = factoryA->createProduct();
productA->use();
// 使用具体工厂 B 创建产品 B
Factory* factoryB = new ConcreteFactoryB();
Product* productB = factoryB->createProduct();
productB->use();
delete factoryA;
delete productA;
delete factoryB;
delete productB;
return 0;
}
相较简单工厂模式,工厂方法模式更加符合开闭原则。工厂方法是使用频率最高的设计模式之一,是很多开源框架和API类库的核心模式。
3. 抽象工厂模式 - 创建产品族
汽车厂为了扩大业务,不只生产汽车了,还生产摩托车。抽象工厂模式可以创建多个工厂和多个产品族(相关的产品)。
抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。
抽象工厂模式的组成:
- 抽象工厂类:工厂方法模式的核心类,提供创建具体产品的接口,由具体工厂类实现。
- 具体工厂类:继承于抽象工厂,实现创建对应具体产品对象的方式。
- 抽象产品类:它是具体产品继承的父类(基类)。
- 具体产品类:具体工厂所创建的对象,就是此类。
创建基类(抽象产品类):
// 汽车抽象类
class Cars
{
public:
virtual ~Cars() {}
virtual void Show() = 0;
};
// 奔驰
class BenziCar: public Cars
{
public:
void Show()
{
std::cout << "我是Benzi car" << std::endl;
}
};
// 摩托车抽象类
class Motors
{
public:
virtual ~Motors() {}
virtual void Show() = 0;
};
// 奔驰
class BenziMotor: public Motors
{
public:
void Show()
{
std::cout << "我是Benzi motor" << std::endl;
}
};
Factory为抽象工厂,提供了创建汽车CreateCars()和摩托车产品CreateMotors()对象的接口。
BenziProducer为具体工厂,实现了创建奔驰汽车和奔驰摩托车的方式。
// 总厂
class Factory
{
public:
virtual Cars *CreateCars() = 0;
virtual Motors *CreateMotors() = 0;
virtual ~Factory() {}
};
// benzi生产者/生产链
class BenziProducer : public Factory
{
public:
Cars *CreateCars()
{
return new BenziCar();
}
Motors *CreateMotors()
{
return new BenziMotor();
}
};
main函数,构造benzi工厂对象,然后创建benzi产品族的汽车和摩托车对象。同样,对象不再使用时,需要手动释放资源。
int main()
{
// ================ 生产Benzi流程 ==================== //
// 生产线
Factory *benziProducer = new BenziProducer();
// 生产汽车
Cars *benziCar = benziProducer ->CreateCars();
// 生产摩托车
Motors *benziMotor = benziProducer ->CreateMotors();
benziCar->Show();
benziMotor->Show();
// 释放资源
delete benziCar;
delete benziMotor;
delete benziProducer;
return 0;
}
适用场景:
- 一系列/一族产品需要被同时使用时,适合使用抽象工厂模式;
- 产品结构稳定,设计完成之后不会向系统中新增或剔除某个产品。
4. 建造者模式 - 建造一座大楼需要
建造者模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
建造者模式的结构包含以下几个角色:
- 抽象建造者(AbstractBuilder):创建一个Product对象的各个部件指定的抽象接口;
- 具体建造者(ConcreteBuilder):实现AbstractBuilder的接口,实现各个部件的具体构造方法和装配方法,并返回创建结果。
- 产品(Product):具体的产品对象
- 指挥者(Director): 构建一个使用Builder接口的对象,安排复杂对象的构建过程,客户端一般只需要与Director交互,指定建造者类型,然后通过构造函数或者setter方法将具体建造者对象传入Director。它主要作用是:隔离客户与对象的生产过程,并负责控制产品对象的生产过程
#include <iostream>
#include <string>
// 产品类
class Product {
public:
void setPartA(const std::string& partA) {
partA_ = partA;
}
void setPartB(const std::string& partB) {
partB_ = partB;
}
void setPartC(const std::string& partC) {
partC_ = partC;
}
void show() {
std::cout << "Product parts: " << partA_ << ", " << partB_ << ", " << partC_ << std::endl;
}
private:
std::string partA_;
std::string partB_;
std::string partC_;
};
// 抽象建造者类
class Builder {
public:
virtual void buildPartA() = 0;
virtual void buildPartB() = 0;
virtual void buildPartC() = 0;
virtual Product* getProduct() = 0;
};
// 具体建造者类 A
class ConcreteBuilderA : public Builder {
public:
void buildPartA() override {
product_->setPartA("PartA of Product A");
}
void buildPartB() override {
product_->setPartB("PartB of Product A");
}
void buildPartC() override {
product_->setPartC("PartC of Product A");
}
Product* getProduct() override {
return product_;
}
private:
Product* product_ = new Product();
};
// 指挥者类
class Director {
public:
void construct(Builder* builder) {
builder->buildPartA();
builder->buildPartB();
builder->buildPartC();
}
};
int main() {
Director director;
ConcreteBuilderA builderA;
director.construct(&builderA);
Product* productA = builderA.getProduct();
productA->show();
delete productA;
return 0;
}
适用环境:
- 需要生成的产品对象有复杂的内部结构(通常包含多个成员变量);
- 产品对象内部属性有一定的生成顺序;
- 同一个创建流程适用于多种不同的产品。
5. 原型模式 - 对象原型与复制
原型模式:使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象。
原型式的结构包含以下几个角色:
- 抽象原型类(AbstractPrototype):声明克隆clone自身的接口
- 具体原型类(ConcretePrototype):实现clone接口
- 客户端(Client):客户端中声明一个抽象原型类,根据客户需求clone具体原型类对象实例
原型模式可以说是“复制”,即克隆,但这个复制不是代码的复制,而是将对象包含的所有属性都创建一份拷贝。但不同的复制操作,可能会产生两种不同的拷贝,即浅拷贝和深拷贝。
#include <iostream>
// 原型基类
class Prototype {
public:
virtual Prototype* clone() = 0;
virtual void show() = 0;
};
// 具体原型类 A
class ConcretePrototypeA : public Prototype {
public:
Prototype* clone() override {
return new ConcretePrototypeA(*this);
}
void show() override {
std::cout << "ConcretePrototypeA" << std::endl;
}
};
// 具体原型类 B
class ConcretePrototypeB : public Prototype {
public:
Prototype* clone() override {
return new ConcretePrototypeB(*this);
}
void show() override {
std::cout << "ConcretePrototypeB" << std::endl;
}
};
int main() {
ConcretePrototypeA prototypeA;
Prototype* clonedA = prototypeA.clone();
clonedA->show();
delete clonedA;
ConcretePrototypeB prototypeB;
Prototype* clonedB = prototypeB.clone();
clonedB->show();
delete clonedB;
return 0;
}
适用环境:
- 当创建新的对象实例较为复杂时,原型模式可以简化创建过程;
- 需要避免使用分层次的工厂类来创建分层次的对象,并且类的实例对象只有一个或很少几个的组合状态,通过复制原型对象得到新实例,比通过使用构造函数创建一个新实例会更加方便。
6. 单例模式 - 唯一实例
单例模式是指在整个系统生命周期内,保证一个类只能产生一个实例,确保该类的唯一性。
单例模式可以保证线程安全,即给共享的资源加把锁,保证每个资源变量每时每刻至多被一个线程占用。
单例模式可以分为懒汉式和饿汉式,两者之间的区别在于创建实例的时间不同。懒汉式只有使用时才会创建实例,这种情况要考虑线程安全;饿汉式初始化就会创建实例,需要时直接调用,不用考虑安全问题。
饿汉式实现:
头文件:
// 饿汉实现 /
class Singleton
{
public:
// 获取单实例
static Singleton* GetInstance();
// 释放单实例,进程退出时调用
static void deleteInstance();
// 打印实例地址
void Print();
private:
// 将其构造和析构成为私有的, 禁止外部构造和析构
Singleton();
~Singleton();
// 将其拷贝构造和赋值构造成为私有函数, 禁止外部拷贝和赋值
Singleton(const Singleton &signal);
const Singleton &operator=(const Singleton &signal);
private:
// 唯一单实例对象指针
static Singleton *g_pSingleton;
};
源文件:
// 代码一运行就初始化创建实例 ,本身就线程安全
Singleton* Singleton::g_pSingleton = new (std::nothrow) Singleton();
Singleton* Singleton::GetInstance()
{
return g_pSingleton;
}
void Singleton::deleteInstance()
{
if (g_pSingleton)
{
delete g_pSingleton;
g_pSingleton = nullptr;
}
}
void Singleton::Print()
{
std::cout << "我的实例内存地址是:" << this << std::endl;
}
Singleton::Singleton()
{
std::cout << "构造函数" << std::endl;
}
Singleton::~Singleton()
{
std::cout << "析构函数" << std::endl;
}
main程序:
#include <iostream>
#include <memory>
#include <mutex>
class Singleton {
public:
static std::shared_ptr<Singleton> getSingleton();
void print() {
std::cout << "Hello World." << std::endl;
}
~Singleton() {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
private:
Singleton() {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
static std::shared_ptr<Singleton> singleton = nullptr;
static std::once_flag singletonFlag;
std::shared_ptr<Singleton> Singleton::getSingleton() {
std::call_once(singletonFlag, [&] {
singleton = std::shared_ptr<Singleton>(new Singleton());
});
return singleton;
}
7. 适配器模式 - 接口的适配
适配器模式主要用于在不兼容的接口之间进行适配,使得它们可以协同工作。
#include <iostream>
// 目标接口类
class Target {
public:
virtual void request() = 0;
};
// 源接口类
class Adaptee {
public:
void specificRequest() {
std::cout << "Adaptee's specific request" << std::endl;
}
};
// 对象适配器类
class Adapter : public Target {
public:
Adapter(Adaptee* adaptee) : adaptee_(adaptee) {}
void request() override {
adaptee_->specificRequest();
}
private:
Adaptee* adaptee_;
};
int main() {
Adaptee adaptee;
Adapter adapter(&adaptee);
adapter.request();
return 0;
}
8. 桥接模式 - 接口的连接
桥接模式主要用于将抽象部分和实现部分分离,使它们可以独立变化,降低它们之间的耦合性。
#include <iostream>
// 实现部分的接口
class Implementor {
public:
virtual void operationImpl() = 0;
};
// 具体实现类 A
class ConcreteImplementorA : public Implementor {
public:
void operationImpl() override {
std::cout << "Concrete Implementor A operation" << std::endl;
}
};
// 具体实现类 B
class ConcreteImplementorB : public Implementor {
public:
void operationImpl() override {
std::cout << "Concrete Implementor B operation" << std::endl;
}
};
// 抽象部分的接口
class Abstraction {
public:
Abstraction(Implementor* implementor) : implementor_(implementor) {}
virtual void operation() {
implementor_->operationImpl();
}
protected:
Implementor* implementor_;
};
// 扩展抽象类
class RefinedAbstraction : public Abstraction {
public:
RefinedAbstraction(Implementor* implementor) : Abstraction(implementor) {}
void otherOperation() {
std::cout << "Other operation of Refined Abstraction" << std::endl;
}
};
int main() {
Implementor* implementorA = new ConcreteImplementorA();
Implementor* implementorB = new ConcreteImplementorB();
Abstraction* abstractionA = new Abstraction(implementorA);
abstractionA->operation();
Abstraction* abstractionB = new RefinedAbstraction(implementorB);
abstractionB->operation();
dynamic_cast<RefinedAbstraction*>(abstractionB)->otherOperation();
delete implementorA;
delete implementorB;
delete abstractionA;
delete abstractionB;
return 0;
}
9. 观察者模式 - 对象随动变化
观察者模式的基本原理,通过观察者模式可以实现对象之间的松耦合,当一个对象的状态发生变化时,所有依赖于它的对象都会得到通知并作出相应的响应。
#include <iostream>
#include <vector>
// 观察者基类
class Observer {
public:
virtual void update(int data) = 0;
};
// 具体观察者类 A
class ConcreteObserverA : public Observer {
public:
void update(int data) override {
std::cout << "Concrete Observer A received data: " << data << std::endl;
}
};
// 具体观察者类 B
class ConcreteObserverB : public Observer {
public:
void update(int data) override {
std::cout << "Concrete Observer B received data: " << data << std::endl;
}
};
// 主题类
class Subject {
private:
int data;
std::vector<Observer*> observers;
public:
void attach(Observer* observer) {
observers.push_back(observer);
}
void setData(int newData) {
data = newData;
notify();
}
void notify() {
for (Observer* observer : observers) {
observer->update(data);
}
}
};
int main() {
ConcreteObserverA observerA;
ConcreteObserverB observerB;
Subject subject;
subject.attach(&observerA);
subject.attach(&observerB);
subject.setData(100);
return 0;
}
10. 装饰者模式 - 增加一些功能
动态地给一个对象添加一些额外的职责,同时不改变其结构。
#include <iostream>
// 组件基类
class Component {
public:
virtual void operation() = 0;
};
// 具体组件类
class ConcreteComponent : public Component {
public:
void operation() override {
std::cout << "Concrete Component Operation" << std::endl;
}
};
// 装饰者基类
class Decorator : public Component {
protected:
Component* component;
public:
Decorator(Component* comp) : component(comp) {}
void operation() override {
if (component != nullptr) {
component->operation();
}
}
};
// 具体装饰者类 A
class ConcreteDecoratorA : public Decorator {
public:
ConcreteDecoratorA(Component* comp) : Decorator(comp) {}
void addBehavior() {
std::cout << "Added Behavior A" << std::endl;
}
void operation() override {
Decorator::operation();
addBehavior();
}
};
// 具体装饰者类 B
class ConcreteDecoratorB : public Decorator {
public:
ConcreteDecoratorB(Component* comp) : Decorator(comp) {}
void addBehavior() {
std::cout << "Added Behavior B" << std::endl;
}
void operation() override {
Decorator::operation();
addBehavior();
}
};
int main() {
ConcreteComponent* component = new ConcreteComponent();
ConcreteDecoratorA* decoratorA = new ConcreteDecoratorA(component);
ConcreteDecoratorB* decoratorB = new ConcreteDecoratorB(decoratorA);
decoratorB->operation();
delete decoratorB;
delete decoratorA;
delete component;
return 0;
}
11. 策略模式 - 运行时选择行为
策略模式是一种行为设计模式,它允许在运行时选择算法的行为。定义一系列算法,把它们封装起来,并且使它们可以互相替换。策略模式可以使算法独立于使用它的客户端而变化。
#include <iostream>
// 策略接口
class Strategy {
public:
virtual void execute() = 0;
};
// 具体策略 A
class ConcreteStrategyA : public Strategy {
public:
void execute() override {
std::cout << "Executing Concrete Strategy A" << std::endl;
}
};
// 具体策略 B
class ConcreteStrategyB : public Strategy {
public:
void execute() override {
std::cout << "Executing Concrete Strategy B" << std::endl;
}
};
// 上下文类
class Context {
private:
Strategy* strategy;
public:
Context(Strategy* s) : strategy(s) {}
void setStrategy(Strategy* s) {
strategy = s;
}
void executeStrategy() {
strategy->execute();
}
};
int main() {
ConcreteStrategyA strategyA;
ConcreteStrategyB strategyB;
Context context(&strategyA);
context.executeStrategy();
context.setStrategy(&strategyB);
context.executeStrategy();
return 0;
}
12. 命令模式 - 参数化行为
命令模式是一种行为设计模式,它将一个请求封装成一个对象,从而使你可以用不同的请求对客户进行参数化,队列或记录请求日志,以及支持可撤销的操作。
#include <iostream>
#include <vector>
// 命令接口
class Command {
public:
virtual void execute() = 0;
};
// 具体命令类 A
class ConcreteCommandA : public Command {
public:
void execute() override {
std::cout << "Executing Concrete Command A" << std::endl;
}
};
// 具体命令类 B
class ConcreteCommandB : public Command {
public:
void execute() override {
std::cout << "Executing Concrete Command B" << std::endl;
}
};
// 执行命令的对象
class Invoker {
private:
std::vector<Command*> commands;
public:
void addCommand(Command* command) {
commands.push_back(command);
}
void executeCommands() {
for (Command* command : commands) {
command->execute();
}
commands.clear();
}
};
int main() {
ConcreteCommandA commandA;
ConcreteCommandB commandB;
Invoker invoker;
invoker.addCommand(&commandA);
invoker.addCommand(&commandB);
invoker.executeCommands();
return 0;
}
13. 状态模式 - 状态随动改变
状态模式是一种行为设计模式,它允许对象在内部状态改变时改变它的行为。状态模式通过将状态封装成独立的类,并将行为委托给当前状态对象来实现。
#include <iostream>
// 状态接口
class State {
public:
virtual void handle() = 0;
};
// 具体状态类 A
class ConcreteStateA : public State {
public:
void handle() override {
std::cout << "Handling in State A" << std::endl;
}
};
// 具体状态类 B
class ConcreteStateB : public State {
public:
void handle() override {
std::cout << "Handling in State B" << std::endl;
}
};
// 上下文类
class Context {
private:
State* state;
public:
Context(State* initialState) : state(initialState) {}
void setState(State* newState) {
state = newState;
}
void request() {
state->handle();
}
};
int main() {
ConcreteStateA stateA;
ConcreteStateB stateB;
Context context(&stateA);
context.request();
context.setState(&stateB);
context.request();
return 0;
}
14. 模板方法 - 算法原型与修改
模板方法模式(Template Method Pattern)是一种行为型设计模式,它定义了一个操作中的算法的骨架,而将一些步骤延迟到子类中。这样可以使子类在不改变算法结构的情况下重新定义某些步骤。
#include <iostream>
// 抽象类定义模板方法
class AbstractClass {
public:
// 模板方法定义了算法的骨架
void templateMethod() {
step1();
step2();
step3();
}
virtual void step1() = 0; // 子类必须实现的步骤1
virtual void step2() = 0; // 子类必须实现的步骤2
void step3() {
std::cout << "Abstract step3" << std::endl;
}
};
// 具体子类实现具体步骤
class ConcreteClassA : public AbstractClass {
public:
void step1() override {
std::cout << "ConcreteClassA step1" << std::endl;
}
void step2() override {
std::cout << "ConcreteClassA step2" << std::endl;
}
};
class ConcreteClassB : public AbstractClass {
public:
void step1() override {
std::cout << "ConcreteClassB step1" << std::endl;
}
void step2() override {
std::cout << "ConcreteClassB step2" << std::endl;
}
};
int main() {
AbstractClass* a = new ConcreteClassA();
AbstractClass* b = new ConcreteClassB();
a->templateMethod();
b->templateMethod();
delete a;
delete b;
return 0;
}
通过模板方法模式,我们可以在父类中定义一个算法的骨架,而将具体实现延迟到子类中,从而实现代码复用和扩展。
以上。