创建型设计模式(Creational Design Patterns) - 5种

[TOC]


设计模式的六大原则

1. 开闭原则(Open Close Principle)(OCP)

开放封闭原则指的是软件实体(类、模块、函数等)应该对扩展是开放的,对修改是封闭的。即当需求变化时,应该通过扩展现有的实体来满足新的需求,而不是修改已有的实体。

2. 单一职责原则(Single-Responsibilitiy Principle)(SRP)

单一职责原则指的是一个类应该只有一个单一的责任,即一个类应该只有一个引起它变化的原因。这样可以确保类的职责单一,使得类更加可维护、可扩展和可复用。

3. 里氏代换原则(Liskov Substitution Principle)(LSP)

里氏替换原则指的是子类应该能够替换其父类,并且不影响程序的正确性。子类应该保持和父类相同的行为规范,不应该改变原有的预期行为。

4. 依赖倒转原则(Dependence Inversion Principle)(DIP)

依赖倒置原则指的是高层模块不应该依赖于低层模块,二者都应该依赖于抽象。抽象不应该依赖于具体实现,而具体实现应该依赖于抽象。这样可以降低模块之间的耦合度,提高系统的灵活性和可维护性。

5. 接口隔离原则(Interface Segregation Principle)(ISP)

接口隔离原则指的是客户端不应该被迫依赖于它们不使用的接口。一个类不应该实现不需要的接口,而应该将其拆分成多个小接口,符合单一职责原则,从而降低类之间的耦合度。

6. 迪米特法则(Law of Demeter)(LDP)

迪米特法则指的是一个对象应该对其他对象有尽可能少的了解。一个类应该尽量减少对其他类的直接依赖,只与其直接的朋友(即与自己关联的对象)通信。这样可以降低类之间的耦合度,提高系统的可维护性和扩展性。

7.合成复用原则(Composite Reuse Principle)(CRP)

合成复用原则指的是尽量使用对象组合/聚合,而不是继承。

  • 设计模式共有23种,主要分三大类
    • 创建型模式 - 5种
    • 结构型模式 - 7种
    • 行为型模式 - 11种

什么是创建型设计模式(Creational Design Patterns)

创建型设计模式(Creational Design Patterns)是一类软件设计模式,主要关注如何有效地创建对象实例,包括对象的创建、初始化、组合和表示等。这些模式提供了一种灵活的方式来创建对象,以满足不同的需求,并可以隐藏对象创建的复杂性。

创建型设计模式包括以下五种常见的模式(原生单抽工厂)

  1. 工厂方法模式(Factory Method Pattern):定义一个用于创建对象的接口,但将具体的对象创建延迟到子类中实现,使得子类可以选择创建哪种对象。

  2. 抽象工厂模式(Abstract Factory Pattern):提供一个接口用于创建一系列相关或相互依赖的对象,而无需指定具体的类。

  3. 单例模式(Singleton Pattern):确保一个类只能创建一个实例,并提供全局访问点。

  4. 原型模式(Prototype Pattern):通过复制现有对象来创建新对象,避免了使用构造函数创建新对象的开销。

  5. 建造者模式(生成器模式)(Builder Pattern):通过一个建造者类来逐步构建复杂对象,从而实现对象的创建和配置的灵活性。


一、简单工厂模式(Simple Factory Pattern)

简单工厂模式(Simple Factory Pattern)是一种创建型设计模式,属于对象创建型模式的一种简单形式。它并不是23种经典设计模式中的一员,但在实际的软件开发中,也经常使用到。

简单工厂模式的主要思想是通过一个工厂类(通常是一个静态类或方法)来封装对象的创建过程,隐藏对象的创建细节,因此又被称为静态工厂方法(Staitic Factory Method),对外提供一个简单的接口来创建对象实例。这样可以将对象的创建逻辑集中管理,从而在客户端代码中实现对象的创建和使用的解耦,简化了客户端的代码。

简单工厂模式的优点是可以将对象的创建和使用解耦,隐藏了对象的创建细节,使得客户端代码更加简洁和易于维护。 但缺点是当需要增加新的产品类时,需要修改工厂类的代码,违反了开闭原则,不够灵活 。因此,简单工厂模式通常适用于对象创建逻辑比较简单且不经常变化的场景。

简单工厂模式

简单工厂模式通常包含以下几个角色:
  1. 工厂类(核心)(Factory Class)

    工厂类负责实现创建对象的内部逻辑,通常包含一个或多个静态方法来创建对象实例。根据客户端的请求,工厂类可以创建不同的对象,并将对象的创建过程封装起来,对外提供简单的接口,可以被外界直接调用,创建所需对象。

  2. 产品类(Product Class)

    产品类是工厂类创建的对象,负责实现具体的功能。不同的产品类通常具有共同的接口或继承自共同的父类,以实现对外提供统一的接口。

    • 抽象产品(Abstract Good)

      工厂类所创建的所有对象的父类,封装了产品对象的公共方法,所有的具体产品为其子类对象。

    • 具体产品(Specific Good)

      简单工厂模式的创建目标,所有被创建的对象都是某个具体类的实例,它要实现抽象产品中声明的抽象方法。

  3. 客户端(Client)

    客户端是调用工厂类来创建对象的代码,通常使用工厂类的静态方法来创建对象,并通过产品类的接口来访问和使用创建的对象。

简单工厂模式参考代码实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <iostream>
#include <string>
using namespace std;

/*
* 简单工厂模式
*/

// 抽象产品
class AbstractProduct
{
public:
virtual void info() = 0; // 声明纯虚函数
virtual ~AbstractProduct() { ; }
};

// 具体产品 A
class ProductA :public AbstractProduct
{
public:
void info()
{
cout << "产品的信息:A" << endl;
}
virtual ~ProductA() { ; }
};

// 具体产品 B
class ProductB :public AbstractProduct
{
public:
void info()
{
cout << "产品的信息:B" << endl;
}
virtual ~ProductB() { ; }
};

// 简单工厂
class SimpleFactory
{
public:
static AbstractProduct* CreateProduct(char type)
{
AbstractProduct* aProduct = nullptr;
switch (type)
{
case 'A':
aProduct = new ProductA();
break;
case 'B':
aProduct = new ProductB();
break;
default:
cout << "没有" << type << "类型产品" << endl;
}
return aProduct;
}
};

int main()
{
// 产品A
AbstractProduct* aProductA = SimpleFactory::CreateProduct('A');
if (aProductA)
{
aProductA->info();
}
// 产品B
AbstractProduct* aProductB = SimpleFactory::CreateProduct('B');
if (aProductB)
{
aProductB->info();
}
}

二、工厂方法模式(Factory Method Pattern)

工厂模式(Factory Pattern)是一种创建型设计模式,用于封装对象的创建过程,使得客户端代码不需要直接依赖于具体的对象类,而是通过工厂类来创建对象。工厂模式可以隐藏对象的创建细节,对外提供统一的接口来创建对象实例,从而提高代码的可维护性、灵活性和可扩展性。

意图:使一个类的实例化延迟到其子类。

在工厂方法模式中,抽象工厂定义了一个用于创建产品对象的工厂方法,具体的产品对象的创建逻辑由具体的工厂类来实现。这样,客户端只需要通过抽象工厂接口来创建产品对象,而不需要直接依赖于具体的产品类和工厂类。这种方式使得客户端代码更加灵活,可以通过切换不同的工厂类来创建不同类型的产品对象,从而实现对象的创建和使用解耦,提高了代码的可维护性和扩展性。

Factory Method Pattern适用于:

  1. 当一个类不知道它所必须创建的对象的类的时候。
  2. 当一个类希望由它的子类来指定它所创建的对象的时候。
  3. 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类使代理者这一信息局部化的时候。

工厂方法模式

工厂方法模式通常包含以下几个角色:
  1. 抽象工厂(Abstract Factory)

    抽象工厂是一个接口或抽象类,定义了一组用于创建产品对象的工厂方法,每个工厂方法对应一个产品族(一组相关的产品),具体的工厂类需要实现抽象工厂接口,来实现具体的对象创建逻辑。

  2. 具体工厂(Concrete Factory)

    具体工厂是实现抽象工厂接口的具体类,负责根据客户端的请求来创建具体的产品对象。

  3. 抽象产品(Abstract Product)

    抽象产品是一个接口或抽象类,定义了产品的通用接口,具体的产品类需要实现抽象产品接口。

  4. 具体产品(Specific Good)

    具体产品是实现抽象产品接口的具体类,负责实现具体的产品功能。

  5. 客户端(Client)

    客户端是调用工厂类来创建对象的代码,通常使用工厂类的静态方法来创建对象,并通过产品类的接口来访问和使用创建的对象。

工厂方法模式参考代码实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include <iostream>
#include <string>
using namespace std;

/*
* 工厂方法模式
*/

// 产品接口
class IProduct
{
public:
virtual void info() = 0; // 声明纯虚函数
virtual ~IProduct() { ; }
};

// 具体产品 A
class ProductA :public IProduct
{
public:
void info()
{
cout << "产品的信息:A" << endl;
}
~ProductA() { ; }
};

// 具体产品 B
class ProductB :public IProduct
{
public:
void info()
{
cout << "产品的信息:B" << endl;
}
~ProductB() { ; }
};

// 工厂
class IFactory
{
public:
virtual IProduct* CreateProduct() = 0;
virtual ~IFactory() { ; }
};

// 工厂A
class FactoryA :public IFactory
{
public:
IProduct* CreateProduct()
{
return new ProductA();
};
~FactoryA() { ; }
};

// 工厂B
class FactoryB :public IFactory
{
public:
IProduct* CreateProduct()
{
return new ProductB();
};
~FactoryB() { ; }
};

int main()
{
// 产品A
IFactory* factoryA = new FactoryA();
IProduct* productA = factoryA->CreateProduct();
productA->info();
// 产品B
IFactory* factoryB = new FactoryB();
IProduct* productB = factoryB->CreateProduct();
productB->info();

delete factoryA;
delete factoryB;
delete productA;
delete productB;
}

三、抽象工厂模式(Abstract Factory Pattern)

抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,属于对象创建型模式。它提供了一种抽象的方式来创建一系列相关或相互依赖的产品对象,而不需要指定具体的产品类。

意图:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。

抽象工厂模式允许客户端通过抽象工厂接口来创建一系列相关的产品对象,这些产品对象可以属于不同的产品族,但遵循相同的接口或抽象类。客户端只需要依赖于抽象工厂和抽象产品接口,而不需要直接依赖于具体的产品类和工厂类。这种方式使得客户端代码更加灵活,可以通过切换不同的工厂类来创建不同产品族的产品对象,从而实现对象的创建和使用解耦,提高了代码的可维护性和扩展性。抽象工厂模式在一些需要创建一系列相关产品对象的场景中特别有用,例如图形界面工具包、数据库访问工具等。

Abstract Factory Pattern适用于:

  1. 一个系统要独立于它的产品的创建、组合和表示时。
  2. 一个系统要由多个产品系列中的一个来配置时。
  3. 当要强调一系列相关的产品对象的设计以便进行联合使用时。
  4. 当提供一个产品类库,只想显示它们的接口而不是实现时。

抽象工厂模式

抽象工厂方法模式通常包含以下几个角色:(同工厂方法模式)
  1. 抽象工厂(Abstract Factory)
  2. 具体工厂(Concrete Factory)
  3. 抽象产品(Abstract Product)
  4. 具体产品(Concrete Product)
  5. 客户端(Client)
抽象工厂方法模式参考代码实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include <iostream>
#include <string>
using namespace std;

/*
* 抽象工厂模式
*/

// 产品A接口
class IProductA
{
public:
virtual void info() = 0; // 声明纯虚函数
virtual ~IProductA() { ; }
};

// 具体产品 A1
class ProductA1 :public IProductA
{
public:
void info()
{
cout << "产品的信息:A1" << endl;
}
~ProductA1() { ; }
};

// 具体产品 A2
class ProductA2 :public IProductA
{
public:
void info()
{
cout << "产品的信息:A2" << endl;
}
~ProductA2() { ; }
};

// 产品B接口
class IProductB
{
public:
virtual void info() = 0; // 声明纯虚函数
virtual ~IProductB() { ; }
};

// 具体产品 B1
class ProductB1 :public IProductB
{
public:
void info()
{
cout << "产品的信息:B1" << endl;
}
~ProductB1() { ; }
};

// 具体产品 B2
class ProductB2 :public IProductB
{
public:
void info()
{
cout << "产品的信息:B2" << endl;
}
~ProductB2() { ; }
};

// 工厂
class IFactory
{
public:
virtual IProductA* CreateProductA() = 0;
virtual IProductB* CreateProductB() = 0;
virtual ~IFactory() { ; }
};

// 工厂1
class Factory1 :public IFactory
{
public:
IProductA* CreateProductA()
{
return new ProductA1();
};
IProductB* CreateProductB()
{
return new ProductB1();
};
~Factory1() { ; }
};

// 工厂2
class Factory2 :public IFactory
{
public:
IProductA* CreateProductA()
{
return new ProductA2();
};
IProductB* CreateProductB()
{
return new ProductB2();
};
~Factory2() { ; }
};

int main()
{
// 产品A
IFactory* factory1 = new Factory1();
IProductA* productA1 = factory1->CreateProductA();
IProductB* productB1 = factory1->CreateProductB();
productA1->info();
productB1->info();
// 产品B
IFactory* factory2 = new Factory2();
IProductA* productA2 = factory2->CreateProductA();
IProductB* productB2 = factory2->CreateProductB();
productA2->info();
productB2->info();
}

四、建造者模式(生成器模式)(Builder Pattern)

建造者模式(Builder Pattern)又称为生成器模式,是一种创建型设计模式,用于将一个复杂对象的构建过程与其表示分离,从而可以灵活地创建不同的对象表示。

生成器模式的核心思想是将复杂对象的构建过程拆分成多个步骤,并由不同的构建者(Builder)负责实现这些步骤,最终通过一个指挥者(Director)来协调构建者的工作,生成最终的产品对象。

意图:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

生成器模式的主要优点是将复杂对象的构建过程封装在构建者对象中,使得客户端可以灵活地配置和控制构建过程,从而实现不同表示的对象构建,而不需要直接操作复杂对象的各个组成部分。生成器模式适用于构建过程复杂、组成部分多样化且可能变化的对象,可以提高代码的可维护性和灵活性,减少客户端与产品对象的耦合。生成器模式在一些需要构建多样化、复杂对象的场景中特别有用,例如创建复杂的数据库查询、构建复杂的报表、生成复杂的配置文件等。

Builder Pattern适用于:

  1. 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的爪给你配方式时。
  2. 当构造过程必须允许被构造的对象有不同的表示时。

生成器模式

生成器模式通常包含以下几个角色:
  1. 产品(Product)

    产品是最终构建的复杂对象,它由多个组成部分组成,可以是一个复杂的对象或者一个对象的组合。

  2. 抽象构建者(Abstract Builder)

    抽象构建者是一个接口或抽象类,定义了构建产品对象的方法,包括构建产品的各个组成部分的方法。

  3. 具体构建者(Concrete Builder)

    具体构建者是实现抽象构建者接口的具体类,负责实现构建产品对象的具体逻辑,包括构建产品的各个组成部分,并最终返回构建好的产品对象。

  4. 指挥者(Director)

    指挥者是一个类,负责使用构建者对象来构建复杂对象。客户端通过与指挥者交互,配置构建者对象的构建顺序和参数,从而控制复杂对象的构建过程。

  5. 客户端(Client)

    客户端是调用生成器模式来构建复杂对象的代码,通过与指挥者和具体构建者对象交互,配置构建参数和调用构建方法,最终获取构建好的产品对象。

生成器模式参考代码实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include <iostream>
#include <string>
#include <list>
#include<vector>
using namespace std;

/*
* 建造者(生成器)模式
*/

// 产品
class CProduct
{
public:
vector<string> parts;
public:
void Add(string part)
{
parts.push_back(part);
}
void Show()
{
cout << "产品的组成:";
for (int i = 0; i < parts.size(); i++)
{
cout << parts[i] << " ";
}
cout << endl;
}
~CProduct() { ; }
};

// 抽象生成器类
class ABuilder
{
public:
virtual void BuildPart() = 0;
virtual CProduct* GetResult() = 0;
virtual ~ABuilder() { ; }
};

// 套餐1
class CBuilder1 :public ABuilder
{
public:
CProduct* product;
public:
void BuildPart()
{
product = new CProduct();
product->Add("A");
product->Add("B");
product->Add("C");
};
CProduct* GetResult()
{
return product;
};
~CBuilder1() { ; }
};

// 套餐2
class CBuilder2 :public ABuilder
{
public:
CProduct* product;
public:
void BuildPart()
{
product = new CProduct();
product->Add("D");
product->Add("E");
product->Add("F");
};
CProduct* GetResult()
{
return product;
};
~CBuilder2() { ; }
};

// 导演
class CDirector
{
public:
void Construct(ABuilder* aBuilder)
{
aBuilder->BuildPart();
};
~CDirector() { ; }
};

int main()
{
CDirector* director = new CDirector();
// 套餐1
ABuilder* builder1 = new CBuilder1();
director->Construct(builder1);
CProduct* product1 = builder1->GetResult();
product1->Show();
// 套餐2
ABuilder* builder2 = new CBuilder2();
director->Construct(builder2);
CProduct* product2 = builder2->GetResult();
product2->Show();
}

五、原型模式(Prototype Pattern)

原型模式(Prototype Pattern)是一种创建型设计模式,用于通过克隆现有对象来创建新对象,而不是通过显式地调用构造函数来创建新对象。

原型模式的核心思想是使用一个现有对象作为原型,通过克隆(深拷贝或浅拷贝)该原型对象来创建新对象。原型模式可以避免创建复杂对象时的构造过程,提高对象创建的效率,并且可以通过复制现有对象来创建新对象,从而减少了重复代码。

意图:用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。

原型模式的主要优点是可以通过克隆现有对象来创建新对象,避免了显式地调用构造函数,提高了对象创建的效率。同时,原型模式可以通过复制现有对象来创建新对象,从而减少了重复代码,增加了灵活性和可维护性。原型模式适用于需要创建多个相似对象的场景,特别是在对象的构造过程较为复杂时可以发挥其优势,例如在创建数据库连接、线程池、缓存等对象时,可以使用原型模式来避免重复构造对象的开销。需要注意的是,原型模式涉及到对象的克隆,需要注意深拷贝和浅拷贝的问题,以确保克隆得到的新对象与原对象在内部状态和外部行为上的一致性。

Prototype Pattern适用于:

  1. 当一个系统应该独立于它的产品创建、构成和表示时。
  2. 当要实例化的类是在运行时刻指定时,例如:通过动态装载。
  3. 为了避免创建一个与产品类层次平行的工厂类层次时。
  4. 当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们,可能比每次用合适的状态手工实例化该类更方便一些。

原型模式

原型模式通常包含以下几个角色:
  1. 原型(Prototype)

    原型是一个接口或抽象类,定义了克隆(拷贝)自己的方法。它是需要被克隆的对象的抽象表示。

  2. 具体原型(Concrete Prototype)

    具体原型是实现原型接口的具体类,实现了克隆自己的方法,用于创建新对象。

  3. 客户端(Client)

    客户端是调用原型模式来创建新对象的代码,通过克隆现有对象来创建新对象,而不是显式地调用构造函数。

原型模式参考代码实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include <iostream>
#include <string>
using namespace std;

/*
* 原型模式
*/

// 抽象原型类
class IPrototype
{
public:
int* value = 0;
public:
virtual IPrototype* Clone() = 0;
~IPrototype() { ; }
};

// 具体原型类(深拷贝)
class PrototypeD :public IPrototype
{
public:
PrototypeD() { value = nullptr; }
PrototypeD(int v) { value = new int(v); }
PrototypeD(const PrototypeD& prototype) // 深拷贝构造函数
{
value = new int(*prototype.value);
}
// 深拷贝赋值操作符
PrototypeD& operator=(const PrototypeD& prototype)
{
if (this == &prototype)
{
return *this;
}
delete value;
value = new int(*prototype.value);
return *this;
}
PrototypeD* Clone()
{
return new PrototypeD(*this);
}
int GetValue() const
{
return *value;
}
~PrototypeD() { ; }
};

// 具体原型类(浅拷贝)
class PrototypeS :public IPrototype
{
public:
PrototypeS() { value = nullptr; }
PrototypeS(int v) { value = new int(v); }
PrototypeS(const PrototypeS& prototype) // 浅拷贝构造函数
{
value = prototype.value;
}
// 浅拷贝赋值操作符
PrototypeS& operator=(const PrototypeS& prototype)
{
if (this == &prototype)
{
return *this;
}
value = prototype.value;
return *this;
}
PrototypeS* Clone()
{
return new PrototypeS(*this);
}
int GetValue() const
{
return *value;
}
~PrototypeS() { ; }
};

int main()
{
// 深拷贝
cout << "深拷贝:" << endl;
PrototypeD prototypeD(10);
PrototypeD prototypeD1 = *prototypeD.Clone();
*prototypeD.value = 30; // 修改原型的值
cout << "prtotypeD 的 value = " << *prototypeD.value << endl;
cout << "prtotypeD1 的 value = " << *prototypeD1.value << endl;

// 浅拷贝
cout << "浅拷贝:" << endl;
PrototypeS prototypeS(100);
PrototypeS prototypeS1 = *prototypeS.Clone();
*prototypeS.value = 200; // 修改原型的值
cout << "prtotypeS 的 value = " << *prototypeS.value << endl;
cout << "prtotypeS1 的 value = " << *prototypeS1.value << endl;
}

六、单例模式(Singleton Pattern)

单例模式(Singleton Pattern)是一种创建型设计模式,用于确保一个类只有一个实例,并且提供一个全局访问点来获取该实例。

在单例模式中,一个类只能创建一个实例,并且提供了一个全局访问点(通常是一个静态方法)来获取这个实例。如果实例不存在,则创建一个新的实例;如果实例已经存在,则直接返回现有的实例,确保整个系统中只有一个实例存在。

意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

单例模式的主要优点是确保一个类只有一个实例存在,可以在整个系统中共享这个唯一实例,避免了多次创建对象的开销。单例模式可以用于需要控制全局资源、配置管理、日志记录等场景,确保系统中只有一个实例来管理这些全局资源,保持一致性和协调性。需要注意的是,单例模式在多线程环境下需要考虑线程安全性,确保在并发访问时不会创建多个实例,可以通过加锁、双重检查锁等方式来保证线程安全性。

Singleton Pattern适用于:

  1. 当类只能由一个实例而且客户可以从一个众所周知的访问的访问它时。
  2. 当这个唯一实例应该是通过子类化可扩展的,并且客户无须更改代码就能使用一个扩展的实例时。

单例模式

单例模式通常包含以下几个角色:
  1. 私有构造函数(Private Constructor)

    单例类的构造函数必须是私有的,这样可以防止外部代码直接通过构造函数创建新的实例。

  2. 私有静态实例变量(Private Static Instance Variable)

    单例类内部维护一个私有的静态实例变量,用于保存单例对象的唯一实例。

  3. 公有静态方法(Public Static Method)

    单例类提供一个公有的静态方法,通常命名为"getInstance()",用于获取单例对象的实例。在该方法中,判断实例是否已经存在,如果不存在,则创建一个新的实例并返回;如果已经存在,则直接返回现有的实例。

单例模式参考代码实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include <iostream>
#include <string>
using namespace std;

/*
* 单例模式
*/

// 懒汉版(Lazy Singleton):单例实例在第一次被使用时才进行初始化,这叫做延迟初始化。
class LazySingleton
{
private:
int value = 0;
static LazySingleton* instance;
private:
LazySingleton() { ; }
~LazySingleton() { ; }
LazySingleton(const LazySingleton&) = delete;
LazySingleton& operator=(const LazySingleton&) = delete;
public:
static LazySingleton* getInstance()
{
if (instance == NULL)
instance = new LazySingleton();
return instance;
}
int GetValue()
{
return value;
}
void SetValue(int v)
{
value = v;
}
};

LazySingleton* LazySingleton::instance = NULL;

// 饿汉版(Eager Singleton):指单例实例在程序运行时被立即执行初始化
class EagerSingleton
{
public:
static EagerSingleton* instance;
private:
int value = 0;
private:
EagerSingleton() { ; }
~EagerSingleton() { ; }
EagerSingleton(const EagerSingleton&) = delete;
EagerSingleton& operator=(const EagerSingleton&) = delete;
public:
int GetValue()
{
return value;
}
void SetValue(int v)
{
value = v;
}
};

EagerSingleton* EagerSingleton::instance = new EagerSingleton;

int main()
{
// 懒汉版
cout << "懒汉版(Lazy Singleton)" << endl;
LazySingleton* singleton1 = LazySingleton::getInstance();
LazySingleton* singleton2 = LazySingleton::getInstance();
cout << "singleton1 的 value = " << singleton1->GetValue() << endl;
cout << "singleton2 的 value = " << singleton2->GetValue() << endl;
singleton1->SetValue(10);
cout << "singleton1 的 value = " << singleton1->GetValue() << endl;
cout << "singleton2 的 value = " << singleton2->GetValue() << endl;

// 饿汉版
cout << "饿汉版(Eager Singleton)" << endl;
EagerSingleton* singleton3 = EagerSingleton::instance;
EagerSingleton* singleton4 = EagerSingleton::instance;
cout << "singleton3 的 value = " << singleton3->GetValue() << endl;
cout << "singleton4 的 value = " << singleton4->GetValue() << endl;
singleton3->SetValue(10);
cout << "singleton3 的 value = " << singleton3->GetValue() << endl;
cout << "singleton4 的 value = " << singleton4->GetValue() << endl;
}