创建型模式
[toc]
一、工厂模式
1.1 简单工厂模式
简单工厂模式由一个工厂类根据传入参数决定创建哪种产品实例,将对象的创建逻辑集中在一处。
类图
代码
cpp
#include <iostream>
#include <string>
using namespace std;
// 抽象水果类
class Fruit {
public:
virtual void getName() = 0;
virtual ~Fruit() {}
};
class Apple : public Fruit {
public:
void getName() override {
cout << "我是苹果" << endl;
}
};
class Banana : public Fruit {
public:
void getName() override {
cout << "我是香蕉" << endl;
}
};
// 简单工厂类
class FruitFactory {
public:
Fruit* createFruit(const string& type) {
if (type == "apple") return new Apple;
if (type == "banana") return new Banana;
return nullptr;
}
};
int main()
{
FruitFactory* factory = new FruitFactory;
Fruit* apple = factory->createFruit("apple");
apple->getName();
Fruit* banana = factory->createFruit("banana");
banana->getName();
delete apple;
delete banana;
delete factory;
return 0;
}优缺点
优点:
- 不需要记住具体类名,甚至连具体参数都不用记忆
- 实现了对象创建和使用的分离
- 系统可扩展性好,无需修改接口和原类
缺点:
- 增加系统中类的个数,复杂度和理解度增加
- 增加了系统的抽象性和理解难度
- 工厂类职责过重,新增产品需修改工厂代码(违反开闭原则)
1.2 工厂方法模式
工厂方法模式为每种产品提供对应的工厂子类,将简单工厂中的工厂类职责拆分,符合开闭原则。
类图
代码
cpp
#include <iostream>
using namespace std;
// 抽象水果类
class Fruit {
public:
virtual void getName() = 0;
virtual ~Fruit() {}
};
class Apple : public Fruit {
public:
void getName() override {
cout << "我是苹果" << endl;
}
};
class Banana : public Fruit {
public:
void getName() override {
cout << "我是香蕉" << endl;
}
};
// 抽象工厂类
class AbstractFactory {
public:
virtual Fruit* createFruit() = 0;
virtual ~AbstractFactory() {}
};
// 苹果工厂:只生产苹果
class AppleFactory : public AbstractFactory {
public:
Fruit* createFruit() override {
return new Apple;
}
};
// 香蕉工厂:只生产香蕉
class BananaFactory : public AbstractFactory {
public:
Fruit* createFruit() override {
return new Banana;
}
};
int main()
{
// 香蕉工厂 → 生产香蕉
AbstractFactory* bananaFactory = new BananaFactory;
Fruit* banana = bananaFactory->createFruit();
banana->getName();
delete bananaFactory;
delete banana;
// 苹果工厂 → 生产苹果
AbstractFactory* appleFactory = new AppleFactory;
Fruit* apple = appleFactory->createFruit();
apple->getName();
delete appleFactory;
delete apple;
return 0;
}💡 简单工厂 → 工厂方法:将工厂类的
switch/if判断拆分为多个工厂子类,每新增产品只需新增对应工厂类,无需修改已有代码。
二、抽象工厂模式
工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问题。但 由于工厂方法模式中的每个工厂只生产一种产品,可能会导致系统中存在大量的工厂类,势必会增加系统的开销。此时,我们可以考虑将一些相关的产品组成一个”产品族”,由同一个工厂来统一生产,这就是抽象工厂模式的基本思想。
2.1 图例
2.2 代码
cpp
#include <iostream>
using namespace std;
// ===== 抽象产品类 =====
class AbstractApple {
public:
virtual void getName() = 0;
virtual ~AbstractApple() {}
};
class AbstractBanana {
public:
virtual void getName() = 0;
virtual ~AbstractBanana() {}
};
class AbstractPear {
public:
virtual void getName() = 0;
virtual ~AbstractPear() {}
};
// ===== 具体产品:美国 =====
class USAApple : public AbstractApple {
public:
void getName() override { cout << "美国苹果" << endl; }
};
class USABanana : public AbstractBanana {
public:
void getName() override { cout << "美国香蕉" << endl; }
};
class USAPear : public AbstractPear {
public:
void getName() override { cout << "美国鸭梨" << endl; }
};
// ===== 具体产品:中国 =====
class ChinaApple : public AbstractApple {
public:
void getName() override { cout << "中国苹果" << endl; }
};
class ChinaBanana : public AbstractBanana {
public:
void getName() override { cout << "中国香蕉" << endl; }
};
class ChinaPear : public AbstractPear {
public:
void getName() override { cout << "中国鸭梨" << endl; }
};
// ===== 具体产品:日本 =====
class JapanApple : public AbstractApple {
public:
void getName() override { cout << "日本苹果" << endl; }
};
class JapanBanana : public AbstractBanana {
public:
void getName() override { cout << "日本香蕉" << endl; }
};
class JapanPear : public AbstractPear {
public:
void getName() override { cout << "日本鸭梨" << endl; }
};
// ===== 抽象工厂类 =====
class AbstractFactory {
public:
virtual AbstractApple* createApple() = 0;
virtual AbstractBanana* createBanana() = 0;
virtual AbstractPear* createPear() = 0;
virtual ~AbstractFactory() {}
};
// ===== 具体工厂 =====
class USAFactory : public AbstractFactory {
public:
AbstractApple* createApple() override { return new USAApple; }
AbstractBanana* createBanana() override { return new USABanana; }
AbstractPear* createPear() override { return new USAPear; }
};
class ChinaFactory : public AbstractFactory {
public:
AbstractApple* createApple() override { return new ChinaApple; }
AbstractBanana* createBanana() override { return new ChinaBanana; }
AbstractPear* createPear() override { return new ChinaPear; }
};
class JapanFactory : public AbstractFactory {
public:
AbstractApple* createApple() override { return new JapanApple; }
AbstractBanana* createBanana() override { return new JapanBanana; }
AbstractPear* createPear() override { return new JapanPear; }
};
int main()
{
// 中国工厂 → 中国苹果、香蕉、鸭梨
AbstractFactory* factory = new ChinaFactory;
AbstractApple* AA = factory->createApple();
AbstractBanana* AB = factory->createBanana();
AbstractPear* AP = factory->createPear();
AA->getName();
AB->getName();
AP->getName();
delete AA;
delete AB;
delete AP;
delete factory;
return 0;
}⚠️ 抽象工厂模式不符合”开闭原则”:新增产品等级结构需修改所有工厂类。
2.3 抽象工厂模式的优缺点
优点:
- 拥有工厂方法模式的优点
- 当一个产品族中的多个对象被设计成一起工作时,能够保证客户端始终只使用同一个产品族中的对象
- 增加新的产品族很方便,无需修改已有系统,符合”开闭原则”
缺点:
- 增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,违背了”开闭原则”
2.4 三种工厂模式对比
简单工厂模式 + “开闭原则” = 工厂方法模式 工厂方法模式 + “产品族” = 抽象工厂模式
借鉴了《Easy搞定设计模式》
三、单例模式
保证一个类只有一个实例存在,同时提供能对该实例加以访问的全局访问方法。
3.1 三个要点
- 某个类只能有一个实例
- 它必须自行创建这个实例
- 它必须自行向整个系统提供这个实例
3.2 角色和职责
Singleton(单例):在单例类的内部实现只生成一个实例,同时提供一个静态的 getInstance() 方法,让客户可以访问其唯一实例;为了防止在外部对其实例化,将其构造函数设计为私有;在单例类内部定义了一个 Singleton 类型的静态对象,作为外部共享的唯一实例。
3.3 单例模式的使用步骤
- 构造函数私有化 — 防止外部直接创建实例
- 提供全局静态方法 — 作为全局访问点获取单例对象
- 定义静态指针 — 指向本类的唯一实例
单例模式类图
3.4 饿汉模式
在程序启动时(类加载时)就创建实例,不管是否使用。
cpp
#include <iostream>
using namespace std;
class Singleton {
public:
static Singleton* getInstance() {
return instance;
}
private:
Singleton() {}
static Singleton* instance;
};
// 静态变量在类外初始化(程序启动即创建)
Singleton* Singleton::instance = new Singleton;
int main()
{
Singleton* s1 = Singleton::getInstance();
Singleton* s2 = Singleton::getInstance();
if (s1 == s2)
cout << "s1 == s2" << endl;
else
cout << "s1 != s2" << endl;
return 0;
}饿汉模式线程安全(初始化在 main 之前完成),但可能浪费资源(未使用也会创建)。
3.5 懒汉模式
在第一次使用时才创建实例,延迟加载。
cpp
class Singleton1 {
public:
static Singleton1* getInstance() {
if (instance1 == nullptr) {
instance1 = new Singleton1;
}
return instance1;
}
private:
Singleton1() {}
static Singleton1* instance1;
};
// 懒汉式初始化:初始为空,首次调用时创建
Singleton1* Singleton1::instance1 = nullptr;⚠️ 懒汉模式在多线程下需加锁保护,否则可能创建多个实例。
饿汉 vs 懒汉对比
3.6 单例模式的应用——打印机
用单例模式实现一个打印机程序,记录打印次数和内容。
cpp
#include <iostream>
#include <string>
using namespace std;
class Printer {
public:
static Printer* getInstance() {
return instance;
}
void print(const string& text) {
cout << "打印内容:" << text << endl;
sequence++;
cout << "打印机今天使用了 " << sequence << " 次" << endl;
}
private:
// 嵌套 Garbo 类,用于程序结束时自动释放单例
class Garbo {
public:
~Garbo() {
if (instance != nullptr) {
delete instance;
instance = nullptr;
}
}
};
Printer() {}
static Printer* instance;
static int sequence;
static Garbo garbo;
};
int Printer::sequence = 0;
Printer* Printer::instance = new Printer;
Printer::Garbo Printer::garbo;
int main()
{
Printer* p1 = Printer::getInstance();
p1->print("一封简历");
Printer* p2 = Printer::getInstance();
p2->print("一份工作汇报");
Printer* p3 = Printer::getInstance();
p3->print("离职申请");
// p1 == p2 == p3,始终是同一个实例
return 0;
}打印机类图
四、总结
以上就是几种常见的创建型设计模式。