2、创建型模式
约 4661 字大约 16 分钟
2025-06-22
定义出的实例对象有且只能有一个
对类的构造进行限制只需要对默认构造和拷贝构造做限制,这两个构造函数能够创建出新的实例(移动构造不会创建新的实例,只会对资源进行转移)
/**
* 单例模式-饿汉
*
*/
class SingletonHungry {
public:
// 删除拷贝构造
SingletonHungry(const SingletonHungry& obj) = delete;
// 删除赋值构造
SingletonHungry& operator=(const SingletonHungry& obj) = delete;
void test(){
cout << this << endl;
}
static SingletonHungry* getInstance() {
return m_sh;
}
~SingletonHungry() {
delete m_sh;
}
private:
SingletonHungry() = default;
static SingletonHungry* m_sh;
};
//静态成员的初始化需要在类的外部进行
SingletonHungry* SingletonHungry::m_sh = new SingletonHungry();
void test(){
SingletonHungry* sh1 = SingletonHungry::getInstance();
SingletonHungry* sh2 = SingletonHungry::getInstance();
sh1->show();
sh2->show();
cout << (sh1 == sh2) << endl;
}
default没有对函数进行修改,不过把函数声明写到哪个保护权限内就将其访问权限修改了 若要进行限制就需要把拷贝构造,拷贝赋值函数使用delete显式删除(也可以使用default设置为默认的但需要把这些函数写在private保护权限中进行限制),不删除默认构造是因为默认构造函数只能把它放在private保护权限内使用default修改,如果使用delete删除就再也无无法创建类的实例了(下面的初始化静态对象要使用)
这样对类进行限制后这个类就无法再构造出实例化对象了,若想要唯一的实例化对象需要在类内创建一个本类的静态成员,且也只能使用类名访问静态属性或方法。如果要对这个修改过的类使用方法也只能使用静态方法 需要在公共权限内设置一个成员函数讲静态成员对象返回给单例对象的使用者
单例模式也分为饿汉模式和懒汉模式
- 饿汉模式:定义类的时候就创建出了单例对象本例就属于饿汉模式
- 懒汉模式:什么时候使用这个单例对象就什么时候创建这个类的单例实例,在把静态成员指针指向空指针。当使用getInstance函数是就代表使用了这个类的实例,因此在懒汉模式需要把静态成员指针指向空,在getInstance里面创建实例并返回
懒汉模式更加节省内存,但在多线程的场景下是有线程安全问题的。所谓线程安全就是多线程可以同时访问这个单例的对象。在多线程下每个线程访问这个类都要创建一个实例。可以加一个互斥锁,让多个线程阻塞,让多个线程依次访问这个单例对象,它就可以避免懒汉模式下多个线程同时访问单例对象创建出多个类的实例的问题。(但一个一个访问也会影响效率)
饿汉模式
可以使用双重检查锁定解决线程安全问题
/**
* 单例模式-懒汉
*/
class SingletonLazy {
public:
SingletonLazy(const SingletonLazy& obj) = delete;
SingletonLazy& operator=(const SingletonLazy& obj) = delete;
void show() { cout << this << endl; }
static SingletonLazy* getInstance() {
if (m_sl == nullptr) {
m_mutex.lock();
if (m_sl == nullptr) {
m_sl = new SingletonLazy();
}
m_mutex.unlock();
}
return m_sl;
}
private:
SingletonLazy() = default;
static SingletonLazy* m_sl;
static mutex m_mutex;
};
SingletonLazy* SingletonLazy::m_sl = nullptr;
mutex SingletonLazy::m_mutex = mutex();
void test() {
SingletonLazy* sl1 = SingletonLazy::getInstance();
SingletonLazy* sl2 = SingletonLazy::getInstance();
sl1->show();
sl2->show();
cout << (sl1 == sl2) << endl;
}
双重检查锁定的问题 假设有两个线程A、B,当线程A 执行到第 8 行时在线程A中 TaskQueue 实例对象 被创建,并赋值给 m_taskQ。
static TaskQueue* getInstance()
{
if (m_taskQ == nullptr)
{
m_mutex.lock();
if (m_taskQ == nullptr)
{
m_taskQ = new TaskQueue;
}
m_mutex.unlock();
}
return m_taskQ;
}
但是实际上 m_taskQ = new TaskQueue; 在执行过程中对应的机器指令可能会被重新排序。正常过程如下:
第一步:分配内存用于保存 TaskQueue 对象。
第二步:在分配的内存中构造一个 TaskQueue 对象(初始化内存)。
第三步:使用 m_taskQ 指针指向分配的内存。
但是被重新排序以后执行顺序可能会变成这样:
第一步:分配内存用于保存 TaskQueue 对象。
第二步:使用 m_taskQ 指针指向分配的内存。
第三步:在分配的内存中构造一个 TaskQueue 对象(初始化内存)。
这样重排序并不影响单线程的执行结果,但是在多线程中就会出问题。如果线程A按照第二种顺序执行机器指令,执行完前两步之后失去CPU时间片被挂起了,此时线程B在第3行处进行指针判断的时候m_taskQ 指针是不为空的,但这个指针指向的内存却没有被初始化,最后线程 B 使用了一个没有被初始化的队列对象就出问题了(出现这种情况是概率问题,需要反复的大量测试问题才可能会出现)。
使用原子变量解决双重检查锁定的问题
class TaskQueue
{
public:
// = delete 代表函数禁用, 也可以将其访问权限设置为私有
TaskQueue(const TaskQueue& obj) = delete;
TaskQueue& operator=(const TaskQueue& obj) = delete;
static TaskQueue* getInstance()
{
TaskQueue* queue = m_taskQ.load();
if (queue == nullptr)
{
// m_mutex.lock(); // 加锁: 方式1
lock_guard<mutex> locker(m_mutex); // 加锁: 方式2
queue = m_taskQ.load();
if (queue == nullptr)
{
queue = new TaskQueue;
m_taskQ.store(queue);
}
// m_mutex.unlock();
}
return queue;
}
void print()
{
cout << "hello, world!!!" << endl;
}
private:
TaskQueue() = default;
static atomic<TaskQueue*> m_taskQ;
static mutex m_mutex;
};
atomic<TaskQueue*> TaskQueue::m_taskQ;
mutex TaskQueue::m_mutex;
int main()
{
TaskQueue* queue = TaskQueue::getInstance();
queue->print();
return 0;
}
可以使用局部静态对象解决线程安全问题
class TaskQueue
{
public:
// = delete 代表函数禁用, 也可以将其访问权限设置为私有
TaskQueue(const TaskQueue& obj) = delete;
TaskQueue& operator=(const TaskQueue& obj) = delete;
static TaskQueue* getInstance()
{
static TaskQueue taskQ;
return &taskQ;
}
void print()
{
cout << "hello, world!!!" << endl;
}
private:
TaskQueue() = default;
};
int main()
{
TaskQueue* queue = TaskQueue::getInstance();
queue->print();
return 0;
}
懒汉模式的缺点是在创建实例对象的时候有安全问题,但这样可以减少内存的浪费(如果用不到就不去申请内存了)。饿汉模式则相反,在我们不需要这个实例对象的时候,它已经被创建出来,占用了一块内存。对于现在的计算机而言,内存容量都是足够大的,这个缺陷可以被无视。
工厂模式
生产对象的 如果需要频繁地用到一个类,我们就可以给这个对象创造一个工厂类,通过工厂类创造出这个对象,这个类怎么来的里面的细节都不需要我们关心这是封装在工厂类里面的。这样可以简化代码而且更易维护。 工厂类可以生产多种对象,但这些对象之间必须是兄弟关系,也就是他们必须同时继承一个父类。 父类之中的虚函数实际上就是接口,子类继承父类后就可以重写虚函数,这样通过同一个工厂类提供的工厂函数创造出的子类也是不一样的
- 在简单工厂模式,工厂类的数量是一个
- 在工厂模式,工厂类是n个
- 在抽象工厂模式,工厂类是也是m个,m>n 适用场景复杂度:抽象工厂模式>工厂模式>简单工厂模式
简单工厂模式
在定义的抽象类中应该提供虚析构函数。如果对于这个抽象类产生了继承关系,并且在子类中重写了父类的虚函数(实现多态)即用父类指针或引用指向子类的对象,并且用父类指针调用子类里面重写的父类的方法。这样这个子类对象被保存到了父类指针里面。如果不提供父类的虚析构函数,在delete时释放的是父类对象,但父类对象保存的是子类对象的地址。不能完全析构子类对象(在释放时只会释放父类数据的内存,但子类新增的数据没有被释放)所以要把父类析构函数设置成虚析构。这样针对析构函数实现多态就能通过父类指针在释放内存时就能完全释放子类调用的内存
如果定义类时只有一个类就没必要设置虚函数和虚析构了,如果添加了,编译器在底层还会给这个类的虚函数提供虚函数表,增加了编译器的负担 如果子类继承父类没有实现多态就没必要提供虚析构 工厂类的制造函数返回值类型应该是父类的指针,当接收制造出来的对象是也是使用父类指针接收,通过父类指针控制
简单工厂模式的特点就是简单,但它也有缺点,当需要新增新的子类这是没有问题是,但工厂类却需要修改代码,根据不同的的需求知道不同的子类,这样就违反了三原则之一的开放封闭原则(封闭:对于已经开发好得类其内部代码是封闭的,不能再对这个类进行修改了。开放:对已经开发好的类的外部是开放的,可以在当前类的外部添加若干个其他的类,对于添加类的功能和数量是没有限制的)。
[!tip] Title 一般一个函数内部的代码量最好不要超过一百行
对于以后不打算扩展的类适合使用简单工厂模式 对于不知道以后在这个类里面需要创建多少个子类的情况适合使用工厂模式
#include <iostream>
using namespace std;
// 简单工厂模式
/**
* 抽象恶魔果实类
*/
class AbstractSmile {
public:
virtual void transform() = 0;
virtual void ability() = 0;
virtual ~AbstractSmile() {}
};
/**
* 山羊恶魔果实
*/
class SheepSmile : public AbstractSmile {
public:
void transform() override { cout << "变身山羊" << endl; }
void ability() override { cout << "变为羊角" << endl; }
};
/**
* 狮子恶魔果实
*/
class LionSmile : public AbstractSmile {
public:
void transform() override { cout << "变身狮子" << endl; }
void ability() override { cout << "豪火球术" << endl; }
};
/**
* 蝙蝠恶魔果实
*/
class BatSmile : public AbstractSmile {
public:
void transform() override { cout << "变身蝙蝠" << endl; }
void ability() override { cout << "声纳引箭" << endl; }
};
/**
* 恶魔果实工厂类
*/
class SmileFactory {
public:
enum class SmileType : char { Sheep, Lion, Bat };
AbstractSmile* createSmile(SmileType type) {
AbstractSmile* smile = nullptr;
switch (type) {
case SmileType::Sheep:
smile = new SheepSmile();
break;
case SmileType::Lion:
smile = new LionSmile();
break;
case SmileType::Bat:
smile = new BatSmile();
break;
default:
break;
}
return smile;
}
};
void test(){
SmileFactory factory;
AbstractSmile* sheep = factory.createSmile(SmileFactory::SmileType::Lion);
sheep->transform();
sheep->ability();
delete sheep;
}
工厂模式
在工厂模式一个工厂类只生产一个子类,简单工厂模式是一对多的关系,工厂模式是一对一的关系。工厂模式也就是对简单工厂模式进行了解耦合,削弱了工厂类的功能 工厂模式需要设置一个抽象类作为父类,因为它将要被继承给多个子类因此也需要虚析构函数
然后制造不同的子类分别实现对应的工厂类继承自抽象工厂类 也是通过父类指针控制子类行为
#include <iostream>
using namespace std;
// 工厂模式
/**
* 抽象恶魔果实类
*/
class AbstractSmile {
public:
virtual void transform() = 0;
virtual void ability() = 0;
virtual ~AbstractSmile() {}
};
/**
* 山羊恶魔果实
*/
class SheepSmile : public AbstractSmile {
public:
void transform() override { cout << "变身山羊" << endl; }
void ability() override { cout << "变为羊角" << endl; }
};
/**
* 狮子恶魔果实
*/
class LionSmile : public AbstractSmile {
public:
void transform() override { cout << "变身狮子" << endl; }
void ability() override { cout << "豪火球术" << endl; }
};
/**
* 蝙蝠恶魔果实
*/
class BatSmile : public AbstractSmile {
public:
void transform() override { cout << "变身蝙蝠" << endl; }
void ability() override { cout << "声纳引箭" << endl; }
};
/**
* 抽象工厂类
*/
class AbstractFactory {
public:
virtual AbstractSmile *createSmile() = 0;
virtual ~AbstractFactory() {}
};
/**
* 山羊恶魔果实工厂
*/
class SheepFactory : public AbstractFactory {
public:
AbstractSmile *createSmile() override { return new SheepSmile(); }
~SheepFactory() { cout << "山羊恶魔果实工厂析构" << endl; }
};
/**
* 狮子恶魔果实工厂
*/
class LionFactory : public AbstractFactory {
public:
AbstractSmile *createSmile() override { return new LionSmile(); }
~LionFactory() { cout << "狮子恶魔果实工厂析构" << endl; }
};
/**
* 蝙蝠恶魔果实工厂
*/
class BatFactory : public AbstractFactory {
public:
AbstractSmile *createSmile() override { return new BatSmile(); }
~BatFactory() { cout << "蝙蝠恶魔果实工厂析构" << endl; }
};
void test(){
AbstractFactory* factory=new LionFactory();
AbstractSmile* sheep = factory->createSmile();
sheep->transform();
sheep->ability();
delete sheep;
delete factory;
}
抽象工厂模式
适用于复杂类的生产 将一个整体类分为一个个部分分别设置对应的工厂类进行生产,每个部分的类可视情况使用简单工厂模式或工厂模式 即抽象工厂模式是简单工厂模式或工厂模式(也可能两者都有)的耦合 最后再由主工厂类将这些零部件组合起来
#include <iostream>
using namespace std;
// 抽象工厂模式
/**
* 船体
*/
class Body {
public:
virtual string getBody() = 0;
~Body() {}
};
// 木头船体
class WoodBody : public Body {
public:
string getBody() { return "木头船体"; }
};
// 钢铁船体
class IronBody : public Body {
public:
string getBody() { return "钢铁船体"; }
};
// 合金船体
class MetalBody : public Body {
public:
string getBody() { return "合金船体"; }
};
/**
* 引擎
*/
class Engine {
public:
virtual string getEngine() = 0;
~Engine() {}
};
// 人力
class HumanEngine : public Engine {
public:
string getEngine() { return "人力引擎"; }
};
// 蒸汽
class SteamEngine : public Engine {
public:
string getEngine() { return "蒸汽引擎"; }
};
// 核能
class NuclearEngine : public Engine {
public:
string getEngine() { return "核能引擎"; }
};
/**
* 武器
*/
class Weapon {
public:
virtual string getWeapon() = 0;
~Weapon() {}
};
// 枪
class Gun : public Weapon {
public:
string getWeapon() { return "枪"; }
};
// 炮
class Cannon : public Weapon {
public:
string getWeapon() { return "炮"; }
};
// 激光
class Laser : public Weapon {
public:
string getWeapon() { return "激光"; }
};
/**
* 船
*/
class Ship {
public:
Ship(Body *body, Engine *engine, Weapon *weapon)
: m_body(body), m_engine(engine), m_weapon(weapon) {}
~Ship() {
delete m_body;
delete m_engine;
delete m_weapon;
}
string getProperty() {
return m_body->getBody() + " " + m_engine->getEngine() + " " +
m_weapon->getWeapon();
}
private:
Body *m_body;
Engine *m_engine;
Weapon *m_weapon;
};
/**
* 工厂
*/
class AbstractFactory {
public:
virtual Ship *createShip() = 0;
virtual ~AbstractFactory() {}
};
// 基础型
class BasicFactory : public AbstractFactory {
public:
Ship *createShip() {
cout << "创建基础型船" << endl;
return new Ship(new WoodBody(), new HumanEngine(), new Gun());
}
};
// 标准型
class StandardFactory : public AbstractFactory {
public:
Ship *createShip() {
cout << "创建标准型船" << endl;
return new Ship(new IronBody(), new SteamEngine(), new Cannon());
}
};
// 旗舰型
class FlagFactory : public AbstractFactory {
public:
Ship *createShip() {
cout << "创建旗舰型船" << endl;
return new Ship(new MetalBody(), new NuclearEngine(), new Laser());
}
};
void test(){
AbstractFactory *factory = new FlagFactory();
Ship *ship = factory->createShip();
cout << ship->getProperty() << endl;
delete ship;
delete factory;
}
生成器(建造者)模式
不管是哪种工厂模式在生产对象的时候都不注重细节 生成器模式就是基于工厂模式改良的,它更专注细节
如果在生产对象的时候内部有比较复杂的流程,这种情况更适合使用生成器模式
可以进一步将用于创建产品的一系列生成器步骤调用抽取成为单独的主管类。 主管类可定义创建步骤的执行顺序, 而生成器则提供这些步骤的实现。 程序中并不一定需要主管类。 客户端代码可直接以特定顺序调用创建步骤。 不过, 主管类中非常适合放入各种例行构造流程, 以便在程序中反复使用。 对于客户端代码来说, 主管类完全隐藏了产品构造细节。 客户端只需要将一个生成器与主管类关联, 然后使用主管类来构造产品, 就能从生成器处获得构造结果了。
示例:
#include <iostream>
#include <map>
#include <vector>
using namespace std;
// 生成器模式
// 桑尼号船
class SunnyShip {
public:
void addParts(string part) { m_parts.emplace_back(part); }
void showParts() {
cout << "桑尼号的部件" << endl;
for (const auto& part : m_parts) {
cout << part << " ";
}
cout << endl;
}
private:
vector<string> m_parts;
};
// 梅丽号船
class MerryShip {
public:
void assemble(string name, string parts) { m_parts.insert({name, parts}); }
void showParts() {
cout << "梅丽号的部件" << endl;
for (const auto& item : m_parts) {
cout << item.first << ":" << item.second << " ";
}
cout << endl;
}
private:
map<string, string> m_parts;
};
// 生成器
class ShipBuilder {
public:
virtual void reset() = 0;
virtual void buildBody() = 0;
virtual void buildEngine() = 0;
virtual void buildWeapon() = 0;
virtual void buildInterior() = 0;
virtual ~ShipBuilder() {}
};
// 桑尼号生成器
class SunnyBuilder :public ShipBuilder {
public:
SunnyBuilder() { reset(); }
~SunnyBuilder() {
if (m_ship) delete m_ship;
}
void reset() override { m_ship = new SunnyShip(); }
SunnyShip* getShip() {
SunnyShip* ship = m_ship;
m_ship = nullptr;
return ship;
}
void buildBody() override { m_ship->addParts("神树亚当"); }
void buildEngine() override { m_ship->addParts("狮吼炮"); }
void buildWeapon() override { m_ship->addParts("可乐内燃机"); }
void buildInterior() override { m_ship->addParts("装修豪华"); }
private:
SunnyShip* m_ship;
};
// 梅丽号生成器
class MerryBuilder :public ShipBuilder {
public:
MerryBuilder() { reset(); }
~MerryBuilder() {
if (m_ship) delete m_ship;
}
void reset() override { m_ship = new MerryShip(); }
MerryShip* getShip() {
MerryShip* ship = m_ship;
m_ship = nullptr;
return ship;
}
void buildBody() override { m_ship->assemble("船体", "神树亚当"); }
void buildEngine() override { m_ship->assemble("武器", "狮吼炮"); }
void buildWeapon() override { m_ship->assemble("引擎", "可乐内燃机"); }
void buildInterior() override { m_ship->assemble("内饰", "装修豪华"); }
private:
MerryShip* m_ship;
};
// 管理者
class Director {
private:
ShipBuilder* m_builder;
public:
void setBuilder(ShipBuilder* builder) { m_builder = builder; }
//基础型
void buildSimpleShip() {
m_builder->buildBody();
m_builder->buildEngine();
}
//标准型
void buildStandardShip() {
buildSimpleShip();
m_builder->buildWeapon();
}
//豪华型
void buildLuxuryShip() {
buildStandardShip();
m_builder->buildInterior();
}
};
//建造桑尼号
void buildSunny(){
Director* director=new Director();
SunnyBuilder* builder=new SunnyBuilder();
//简约型
director->setBuilder(builder);
director->buildSimpleShip();
SunnyShip* ship=builder->getShip();
ship->showParts();
delete ship;
//标准型
builder->reset();
director->setBuilder(builder);
director->buildStandardShip();
ship=builder->getShip();
ship->showParts();
delete ship;
//豪华型
builder->reset();
director->setBuilder(builder);
director->buildLuxuryShip();
ship=builder->getShip();
ship->showParts();
delete ship;
delete builder;
delete director;
}
//建造梅丽号
void buildMerry(){
Director* director=new Director();
MerryBuilder* builder=new MerryBuilder();
//简约型
director->setBuilder(builder);
director->buildSimpleShip();
MerryShip* ship=builder->getShip();
ship->showParts();
delete ship;
//标准型
builder->reset();
director->setBuilder(builder);
director->buildStandardShip();
ship=builder->getShip();
ship->showParts();
//豪华型
builder->reset();
director->setBuilder(builder);
director->buildLuxuryShip();
ship=builder->getShip();
ship->showParts();
delete ship;
delete builder;
delete director;
}
void test(){
buildSunny();
buildMerry();
}
原型模式
克隆是一种最直接、最快捷的创建新对象的方式,它不仅隐藏了创建新对象的诸多细节,还保留了源对象的属性信息,保证了这两个对象能够一模一样。
原型模式就是能够复制已有的对象,而又无需使代码依赖它们所属的类。换种说法,就是通过已有对象克隆出另一个新的对象,并且克隆这个对象不需要使用构造函数。
通过一个已有对象克隆出一个新的对象。一个拷贝构造函数就能搞定的事情为啥还要搞出一种设计模式呢? 有时想要通过父类指针或引用把指向的子类对象克隆出来 克隆可能会在父类和子类之间进行,并且可能是动态的,很明显通过父类的拷贝构造函数无法实现对子类对象的拷贝,其实这就是一个多态,我们需要给父类提供一个克隆函数并且是一个虚函数。
#include <iostream>
using namespace std;
// 原型模式
class GermaSoldier {
public:
virtual GermaSoldier* clone() = 0;
virtual void show() = 0;
virtual ~GermaSoldier() {}
};
// 士兵
class Soldier66 : public GermaSoldier {
public:
GermaSoldier* clone() override { return new Soldier66(*this); }
void show() override { cout << "我是士兵66" << endl; }
};
// 士兵
class Soldier99 : public GermaSoldier {
public:
GermaSoldier* clone() override { return new Soldier99(*this); }
void show() override { cout << "我是士兵99" << endl; }
};
void test(){
GermaSoldier* soldier66 = new Soldier66();
GermaSoldier* soldier = soldier66->clone();
soldier->show();
delete soldier66;
delete soldier;
GermaSoldier* soldier99 = new Soldier99();
soldier = soldier99->clone();
soldier->show();
delete soldier99;
delete soldier;
}
贡献者
版权所有
版权归属:PinkDopeyBug