Factory Method (工厂方法)

工厂方法模式是一种创建型设计模式,其在父类中提供一个创建对象的方法,允许子类决定实例化对象的类型。

我们需要定义两个抽象类:产品基类Product和工厂基类Factory,后者提供创建产品的方法createProduct()。 具体产品(ProductAProductB)需要继承自产品基类Product。 每一个产品都需要提供配套的工厂(FactoryAFactoryB),工厂需要继承自工厂基类Factory,对创建产品的方法提供不同的实现。

示例代码如下

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
#include <iostream>
#include <memory>

// 产品接口
struct Product {
virtual void describe() const = 0;
virtual ~Product() = default;
};

// 产品A
struct ProductA : Product {
void describe() const override { std::cout << "This is Product A.\n"; }
};

// 产品B
struct ProductB : Product {
void describe() const override { std::cout << "This is Product B.\n"; }
};

// 工厂接口
struct Factory {
virtual std::unique_ptr<Product> createProduct() const = 0;
virtual ~Factory() = default;
};

// 工厂A
struct FactoryA : Factory {
std::unique_ptr<Product> createProduct() const override {
return std::make_unique<ProductA>();
}
};

// 工厂B
struct FactoryB : Factory {
std::unique_ptr<Product> createProduct() const override {
return std::make_unique<ProductB>();
}
};

// 客户端代码
void clientCode(const Factory &factory) {
auto product = factory.createProduct();
product->describe();
}

int main() {
std::cout << "Client: Working with a Factory A:\n";
FactoryA productAFactory;
clientCode(productAFactory);

std::cout << "\nClient: Working with a Factory B:\n";
FactoryB productBFactory;
clientCode(productBFactory);

return 0;
}

Abstract Factory (抽象工厂)

抽象工厂模式是一种创建型设计模式,它能创建一系列相关的对象,而无需指定其具体类。

我们需要定义多个抽象产品接口(AbstractProductAAbstractProductB), 每个抽象产品接口有不同的实现(ProductA1ProductA2ProductB1ProductB2)。

我们还需要定义一个抽象工厂接口(AbstractFactory),以及两个具体工厂类(ConcreteFactory1ConcreteFactory2), 它们可以提供不同的产品创建方案,在多个产品的不同实现之间自由搭配:

  • ConcreteFactory1 提供 ProductA1ProductB1 的创建
  • ConcreteFactory2 提供 ProductA2ProductB2 的创建

示例代码如下

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 <memory>

// 产品A接口
struct AbstractProductA {
virtual void describe() const = 0;
virtual ~AbstractProductA() = default;
};

// 产品B接口
struct AbstractProductB {
virtual void describe() const = 0;
virtual ~AbstractProductB() = default;
};

// 具体产品A1
struct ProductA1 : AbstractProductA {
void describe() const override { std::cout << "This is Product A1.\n"; }
};

// 具体产品A2
struct ProductA2 : AbstractProductA {
void describe() const override { std::cout << "This is Product A2.\n"; }
};

// 具体产品B1
struct ProductB1 : AbstractProductB {
void describe() const override { std::cout << "This is Product B1.\n"; }
};

// 具体产品B2
struct ProductB2 : AbstractProductB {
void describe() const override { std::cout << "This is Product B2.\n"; }
};

// 抽象工厂接口
struct AbstractFactory {
virtual std::unique_ptr<AbstractProductA> createProductA() const = 0;
virtual std::unique_ptr<AbstractProductB> createProductB() const = 0;
virtual ~AbstractFactory() = default;
};

// 具体工厂1
struct ConcreteFactory1 : AbstractFactory {
std::unique_ptr<AbstractProductA> createProductA() const override {
return std::make_unique<ProductA1>();
}

std::unique_ptr<AbstractProductB> createProductB() const override {
return std::make_unique<ProductB1>();
}
};

// 具体工厂2
struct ConcreteFactory2 : AbstractFactory {
std::unique_ptr<AbstractProductA> createProductA() const override {
return std::make_unique<ProductA2>();
}

std::unique_ptr<AbstractProductB> createProductB() const override {
return std::make_unique<ProductB2>();
}
};

// 客户端代码
void clientCode(const AbstractFactory &factory) {
auto productA = factory.createProductA();
auto productB = factory.createProductB();
productA->describe();
productB->describe();
}

int main() {
std::cout << "Client: Testing client code with the first factory type:\n";
ConcreteFactory1 factory1;
clientCode(factory1);

std::cout << "\nClient: Testing the same client code with the second "
"factory type:\n";
ConcreteFactory2 factory2;
clientCode(factory2);

return 0;
}

Builder (建造者/生成器)

建造者模式是一种创建型设计模式,又称为生成器模式,它允许我们使用简单的创建代码生成具有复杂配置的对象。

产品类House的配置比较繁琐:需要调用不同的接口,可能需要传递很多参数,可能还与顺序相关。 我们使用建造者类HouseBuilder将配置过程打包,提供成套的方案:

  • 基本房屋 buildBasicHouse()
  • 完整房屋 buildFullHouse()

调用者可以通过HouseBuilder方便地完成对象的创建,同时House也保留了灵活的配置能力。

示例代码如下

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
#include <iostream>
#include <memory>
#include <string>

// 产品类
class House {
public:
void setFoundation(const std::string &foundation) {
m_foundation = foundation;
}

void setStructure(const std::string &structure) { m_structure = structure; }

void setRoof(const std::string &roof) { m_roof = roof; }

void setInterior(const std::string &interior) { m_interior = interior; }

void describe() const {
std::cout << "House with the following parts:\n";
std::cout << " - Foundation: " << m_foundation << "\n";
std::cout << " - Structure: " << m_structure << "\n";
std::cout << " - Roof: " << m_roof << "\n";
std::cout << " - Interior: " << m_interior << "\n";
}

private:
std::string m_foundation;
std::string m_structure;
std::string m_roof;
std::string m_interior;
};

// 建造者类
class HouseBuilder {
public:
HouseBuilder() { m_house = std::make_unique<House>(); }

HouseBuilder &buildFullHouse() {
m_house->setFoundation("Concrete");
m_house->setStructure("Wood");
m_house->setRoof("Shingles");
m_house->setInterior("Drywall");
return *this;
}

HouseBuilder &buildBasicHouse() {
m_house->setFoundation("Concrete");
m_house->setStructure("Wood");
return *this;
}

std::unique_ptr<House> getHouse() { return std::move(m_house); }

private:
std::unique_ptr<House> m_house;
};

int main() {
// 客户端代码
std::cout << "Building a full house:\n";
auto fullHouse = HouseBuilder{}.buildFullHouse().getHouse();
fullHouse->describe();

std::cout << "Building a basic house:\n";
auto basicHouse = HouseBuilder{}.buildBasicHouse().getHouse();
basicHouse->describe();

return 0;
}

建造者模式的核心就是把具有复杂配置的对象的创建过程简化,上面代码提供的只是一种示例,还有不同的建造者实现:

  • 除了提供成套的创建方案,HouseBuilder也可以提供分步创建的接口,客户端可以使用链式调用完成分步创建,在创建过程中,HouseBuilder还可以提供reset()重置之前的配置。
  • 可以直接将建造者HouseBuilder声明为House的友元,从而完全掌握后者的创建:House自身不再需要提供各种配置接口,各种接口可以前移到HouseBuilder中。
  • 如果House没有提供各种配置接口,只提供了一个具有很多参数的构造方法,那么HouseBuilder可以在内部记录下对应的参数列表,最后一步调用构造方法完成创建。对于参数列表的记录可以直接实现,例如作为HouseBuilder的公开数据成员即可。

使用示例如下(对应的代码略)

1
auto house = HouseBuilder{}.setFoundation("Concrete").setStructure("Wood").getHouse();

C++提供的右值引用和移动也可以用于这里的建造者模式:让建造者单步构造过程的返回值是右值,并且对返回值要求[[nodiscard]]

Prototype (原型)

原型模式是一种创建型设计模式,允许我们复制已有对象,同时无需使代码依赖它们所属的类。(支持复制的对象称为原型,通常提供名为clone()的方法)

抽象原型类AbstractPrototype要求提供clone()接口,具体的原型类PrototypeAPrototypeB继承并实现了clone()方法。

示例代码如下

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
#include <iostream>
#include <memory>

// 抽象原型类
class AbstractPrototype {
public:
virtual ~AbstractPrototype() = default;
virtual std::unique_ptr<AbstractPrototype> clone() const = 0;
virtual void print() const = 0;
};

// 具体原型类A
class PrototypeA : public AbstractPrototype {
public:
explicit PrototypeA(int field) : m_field(field) {}

PrototypeA(const PrototypeA &other) : m_field(other.m_field) {}

PrototypeA &operator=(const PrototypeA &) = default;
PrototypeA &operator=(PrototypeA &&) = default;
PrototypeA(PrototypeA &&) = default;
~PrototypeA() override = default;

std::unique_ptr<AbstractPrototype> clone() const override {
return std::make_unique<PrototypeA>(*this);
}

void print() const override {
std::cout << "PrototypeA: " << m_field << std::endl;
}

private:
int m_field;
};

// 具体原型类B
class PrototypeB : public AbstractPrototype {
public:
explicit PrototypeB(std::string field) : m_field(std::move(field)) {}

PrototypeB(const PrototypeB &other) : m_field(other.m_field) {}

PrototypeB(PrototypeB &&) = default;
PrototypeB &operator=(const PrototypeB &) = default;
PrototypeB &operator=(PrototypeB &&) = default;
~PrototypeB() override = default;

std::unique_ptr<AbstractPrototype> clone() const override {
return std::make_unique<PrototypeB>(*this);
}

void print() const override {
std::cout << "PrototypeB: " << m_field << std::endl;
}

private:
std::string m_field;
};

int main() {
// 创建原型对象
auto prototypeA = std::make_unique<PrototypeA>(10);
auto prototypeB = std::make_unique<PrototypeB>("example");

// 克隆对象
auto cloneA = prototypeA->clone();
auto cloneB = prototypeB->clone();

// 打印克隆对象的信息
cloneA->print();
cloneB->print();

return 0;
}

Singleton (单例)

单例模式是一种创建型设计模式,它能够保证一个类只有一个实例,并提供访问该实例的全局方法。按照构造时机可以分为饿汉版(程序启动时构造)和懒汉版(第一次调用时构造)。

单例模式可以说是最简单的设计模式,对于Java这种完全面向对象的语言才有必要性,对于C++来说,直接使用全局变量或静态变量就可以实现单例的基本效果。 但是即使在C++中,我们一般也不会采用全局变量的方式,因为存在相互依赖的全局变量构造和析构顺序不确定,而且我们有时希望延迟构造时机到第一次调用时。

C++中有很多种方式都可以实现单例模式,下面提供几种示例。

基于类的静态变量(饿汉版)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Singleton {
protected:
Singleton() { std::cout << "Singleton: call Constructor\n"; };

static Singleton demo; // declare
public:
Singleton(const Singleton &) = delete;
Singleton &operator=(const Singleton &) = delete;

virtual ~Singleton() { std::cout << "Singleton: call Destructor\n"; }

static Singleton &get_instance() { return demo; }
};

Singleton Singleton::demo; // define

这里在类外的定义是必要的,否则在使用单例时会触发编译错误。

基于类的静态函数的局部静态变量(懒汉版)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Singleton {
protected:
Singleton() { std::cout << "Singleton: call Constructor\n"; };

public:
Singleton(const Singleton &) = delete;
Singleton &operator=(const Singleton &) = delete;

virtual ~Singleton() { std::cout << "Singleton: call Destructor\n"; }

static Singleton &get_instance() {
static Singleton demo;
return demo;
}
};

如果希望用new在堆上创建单例对象,就需要做很多保护措施确保线程安全和异常安全等,例如下面的饿汉版单例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Singleton {
protected:
Singleton() { std::cout << "Singleton: call Constructor\n"; };

inline static std::atomic<Singleton *> demo{nullptr};
inline static std::mutex lock;

public:
Singleton(const Singleton &) = delete;
Singleton &operator=(const Singleton &) = delete;

virtual ~Singleton() { std::cout << "Singleton: call Destructor\n"; }

static Singleton *get_instance() {
if (demo == nullptr) {
std::lock_guard lc{lock};
if (demo == nullptr) { demo = new Singleton(); }
}
return demo;
}
};

对于单例模式的使用是有争议的:

  • 单例模式就像全局变量一样,到处都可以对其访问和修改,这不利于代码解耦,给代码测试和调试带来困难;
  • 单例模式需要关注线程安全,增加了代码复杂度;
  • 对于一个需要保证全局唯一性的资源管理类,才有必要使用单例模式。