创建型模式提供了创建对象的机制,能够提升已有代码的灵活性和可复用性。
1.工厂方法
工厂方法亦称虚拟构造函数、Virtual Constructor、Factory Method。其在父类中提供一个创建对象的 方法,允许子类决定实例化对象 的类型。
工厂方法可以总结为:倒反天罡(即子类可以修改父类的返回类型)
子类通过重写父类的createTransport()方法,让父类创建不同类型的产品。
但是也提出了要求:
(1).这些产品必须有相同的基类或接口
(2).基类中的工厂方法的返回值类型必须是产品共有的接口
调用工厂方法的代码(通常被称为客户端代码)无需了解不同子类返回实际对象之间的差别。客户端将所有产品视为抽象的运输。 客户端知道所有运输对象都提供交付方法,但是并不关心其具体实现方式。
结构
(1)产品:创建一个Product类,在类中声明一个doStuff()方法
(2)具体产品:创建两个具体的类A,B
(3)创建者:声明一个接口,这个接口就是客户端,这里要能创建产品,并且能用产品做事。我们不需要知道产品的类型。
(4)具体创建者:重写两个具体的构造函数,返回不同类型的产品。
可以将工厂方法声明为抽象方法,强制要求每个子类以不同方式实现该方法。
工厂方法的最终目的不是生产东西,而是执行相应的业务逻辑。
实例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
// 产品接口中将声明所有具体产品都必须实现的操作
class Button {
public:
virtual void render() = 0;
virtual void onClick(std::function<void()> f) = 0;
virtual ~Button() = default;
};
// 具体产品需提供产品接口的各种实现
class WindowsButton : public Button {
public:
void render() override {
// 根据 Windows 样式渲染按钮
std::cout << "Rendering button in Windows style.\n";
}
void onClick(std::function<void()> f) override {
// 绑定本地操作系统点击事件
std::cout << "Windows button clicked.\n";
f();
}
};
class HTMLButton : public Button {
public:
void render() override {
// 返回一个按钮的 HTML 表述
std::cout << "Rendering button in HTML style.\n";
}
void onClick(std::function<void()> f) override {
// 绑定网络浏览器的点击事件
std::cout << "HTML button clicked.\n";
f();
}
};
// 创建者还可提供一些工厂方法的默认实现
class Dialog {
public:
virtual std::shared_ptr<Button> createButton() = 0;
// 创建者的主要职责并非是创建产品。包含一些核心业务逻辑
void render() {
std::shared_ptr<Button> okButton = createButton();
okButton->onClick([this]() { closeDialog(); });
okButton->render();
}
virtual ~Dialog() = default;
protected:
void closeDialog() {
std::cout << "Dialog closed.\n";
}
};
// 具体创建者将重写工厂方法以改变其所返回的产品类型
class WindowsDialog : public Dialog {
public:
std::shared_ptr<Button> createButton() override {
return std::make_shared<WindowsButton>();
}
};
class WebDialog : public Dialog {
public:
std::shared_ptr<Button> createButton() override {
return std::make_shared<HTMLInputElement>();
}
};
// 程序根据当前配置或环境设定选择创建者的类型
class Application {
private:
std::shared_ptr<Dialog> dialog;
public:
void initialize() {
// 模拟读取配置文件
std::string configOS = "Windows"; // 这里可以是"Windows"或"Web"
if (configOS == "Windows") {
dialog = std::make_shared<WindowsDialog>();
} else if (configOS == "Web") {
dialog = std::make_shared<WebDialog>();
} else {
throw std::runtime_error("错误!未知的操作系统。");
}
}
void main() {
initialize();
dialog->render();
}
};
int main() {
try {
Application app;
app.main();
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
}
return 0;
}
使用场景
(1)当你在编写代码的过程中,如果无法预知对象确切类别及其依赖关系时,可使用工厂方法。
工厂方法将创建产品的代码与实际使用产品的代码分离,从而能在不影响其他代码的情况下扩展产品创建部分代码。(例如,如果需要向应用中添加一种新产品,你只需要开发新的创建者子类,然后重写其工厂方法即可。)
(2)如果你希望用户能扩展你软件库或框架的内部组件,可使用工厂方法。
(3)如果你希望复用现有对象来节省系统资源,而不是每次都重新创建对象,可使用工厂方法。
在处理大型资源密集型对象(比如数据库连接、文件系统和网络资源)时,你会经常碰到这种资源需求。
复用对象的方法:
(1)创建储存空间存放已经创建的对象。
(2)当请求对象时,程序将在对象池中搜索可用对象。
(3)然后将其返回给客户端代码。
(4)如果没有可用对象,程序则创建一个新对象(并将其添加到对象池中)。
我们需要一个既能够创建新对象,又可以重用现有对象的普通方法。
- 让所有产品都遵循同一接口。该接口必须声明对所有产品都有意义的方法。
- 在创建类中添加一个空的工厂方法。该方法的返回类型必须遵循通用的产品接口。
- 在创建者代码中找到对于产品构造函数的所有引用。将它们依次替换为对于工厂方法的调用,同时将创建产品的代码移入工厂方法。你可能需要在工厂方法中添加临时参数来控制返回的产品类型。
- 现在,为工厂方法中的每种产品编写一个创建者子类,然后在子类中重写工厂方法,并将基本方法中的相关创建代码移动到工厂方法中。
- 如果应用中的产品类型太多,那么为每个产品创建子类并无太大必要,这时你也可以在子类中复用基类中的控制参数。
例如,设想你有以下一些层次结构的类。基类 邮件 及其子类 航空邮件 和 陆路邮件 ; 运输 及其子类 飞机 , 卡车
和 火车 。 航空邮件 仅使用 飞机 对象,而 陆路邮件 则会同时使用 卡车 和 火车 对象。你可以编写一个新的子类
(例如 火车邮件 )来处理这两种情况,但是还有其他可选的方案。客户端代码可以给 陆路邮件 类传递一个参数,用
于控制其希望获得的产品。 - 如果代码经过上述移动后,基础工厂方法中已经没有任何代码,你可以将其转变为抽象类。如果基础工厂方法中还有其
他语句,你可以将其设置为该方法的默认行为。
2.抽象工厂
抽象工厂是一种创建型设计模式,它能创建一系列相关的对象,而无需指定其具体类。
抽象工厂模式建议为系列中的每件产品明确声明接口(例如椅子、沙发或咖啡桌)。然后,确保所有产品变体都继承这些接口。例如,所有风格的椅子都实现椅子接口;所有风格的咖啡桌都实现咖啡桌接口,以此类推。接下来,我们需要声明抽象工厂——包含系列中所有产品构造方法的接口。例如 createChair 创建椅子、createSofa创建沙发createCoffeeTable 创建咖啡桌。这些方法必须返回抽象产品类型,即我们之前抽取的那些接口:椅子,沙发 和 咖啡桌 等等。
结构
(1)抽象产品:为构成系列产品的一组不同但相关的产品声明接口。(桌子和椅子)
(2)具体产品:是抽象产品的多种不同类型实现。不同风格的椅子放在同一个工厂的前提是它们都是椅子
(3)具体工厂:实现抽象工厂的构建方法。。每个具体工厂都对应特定产品变体,且仅创建此种产品变体(各种椅子的变体)
(4)客户端的工厂继承的是抽象的工厂类,目的是为了不和特定产品耦合。客户端得到的产品可以与任何具体工厂/产品变体交互。
实例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
123
124
125
// 抽象工厂接口
class Button {
public:
virtual void paint() = 0;
};
class Checkbox {
public:
virtual void paint() = 0;
};
class GUIFactory {
public:
virtual std::shared_ptr<Button> createButton() = 0;
virtual std::shared_ptr<Checkbox> createCheckbox() = 0;
};
// 具体工厂
class WinButton : public Button {
public:
void paint() override {
// 根据 Windows 样式渲染按钮
std::cout << "Rendering button in Windows style.\n";
}
};
class MacButton : public Button {
public:
void paint() override {
// 根据 macOS 样式渲染按钮
std::cout << "Rendering button in macOS style.\n";
}
};
class WinCheckbox : public Checkbox {
public:
void paint() override {
// 根据 Windows 样式渲染复选框
std::cout << "Rendering checkbox in Windows style.\n";
}
};
class MacCheckbox : public Checkbox {
public:
void paint() override {
// 根据 macOS 样式渲染复选框
std::cout << "Rendering checkbox in macOS style.\n";
}
};
class WinFactory : public GUIFactory {
public:
std::shared_ptr<Button> createButton() override {
return std::make_shared<WinButton>();
}
std::shared_ptr<Checkbox> createCheckbox() override {
return std::make_shared<WinCheckbox>();
}
};
class MacFactory : public GUIFactory {
public:
std::shared_ptr<Button> createButton() override {
return std::make_shared<MacButton>();
}
std::shared_ptr<Checkbox> createCheckbox() override {
return std::make_shared<MacCheckbox>();
}
};
// 客户端代码
class Application {
private:
std::shared_ptr<GUIFactory> factory;
std::shared_ptr<Button> button;
public:
Application(std::shared_ptr<GUIFactory> factory) : factory(factory) {}
void createUI() {
button = factory->createButton();
}
void paint() {
if (button) {
button->paint();
}
}
};
class ApplicationConfigurator {
public:
static void main() {
// 读取配置文件,确定操作系统(此处使用硬编码模拟配置)
std::string configOS = "Windows"; // 模拟读取的配置
std::shared_ptr<GUIFactory> factory;
if (configOS == "Windows") {
factory = std::make_shared<WinFactory>();
} else if (configOS == "Mac") {
factory = std::make_shared<MacFactory>();
} else {
throw std::runtime_error("错误!未知的操作系统。");
}
Application app(factory);
app.createUI();
app.paint();
}
};
int main() {
try {
ApplicationConfigurator::main();
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
}
return 0;
}