一、概述
在软件系统中,有时候面临着复杂的对象创建,该对象由一定算法构成的子对象组成,由于需求变化,这些子对象会经常变换,但组合在一起的算法却是稳定的。生成器模式可以处理这类对象的构建,它提供了一种封装机制来隔离各类子对象的变化,从而保证系统的稳定。
二、生成器模式
生成器模式将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。其结构图如下:
- Builder为创建Product对象的各个子对象指定抽象接口。
- ConcreteBuilder实现了Builder接口,用于创建Product对象的各个子对象。
- Director使用Builder来创建Product对象。
- Product表示被构造的复杂对象。
三、示例
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
|
using System; using System.Collections.Generic; using System.Text; namespace BuilderPattern { /// <summary> /// 所有课程 /// </summary> public class Coures { /// <summary> /// 保存课程信息 /// </summary> IDictionary< string , decimal > coures = new Dictionary< string , decimal >(); /// <summary> /// 选课 /// </summary> /// <param name="serialNumber"></param> /// <param name="score"></param> public void Select( string serialNumber, decimal score) { coures.Add(serialNumber, score); } /// <summary> /// 计算总学分 /// </summary> /// <returns>总学分</returns> public decimal ComputeScores() { decimal scores = 0; foreach (KeyValuePair< string , decimal > kvp in coures) { Console.WriteLine(kvp.Key + ":" + kvp.Value); Console.WriteLine( " " ); scores += kvp.Value; } return scores; } } /// <summary> /// 选课建造者抽象类,表现(下面的抽象函数)是相对稳定的。 /// </summary> public abstract class Builder { /// <summary> /// 必修课程成绩 /// </summary> public abstract void BuildCompulsory(); /// <summary> /// 选修课程成绩 /// </summary> public abstract void BuildElective(); /// <summary> /// 限制课程成绩 /// </summary> public abstract void BuildRestriction(); /// <summary> /// 获得课程字典对象 /// </summary> /// <returns></returns> public abstract Coures GetCoures(); } /// <summary> /// 本科生选课成绩 /// </summary> public class UndergraduateBuilder : Builder { private Coures coures = new Coures(); /// <summary> /// 本科生选必修课程成绩 /// </summary> public override void BuildCompulsory() { coures.Select( "001" , 80M); } /// <summary> /// 本科生选选修课程成绩 /// </summary> public override void BuildElective() { coures.Select( "101" , 85M); } /// <summary> /// 本科生选限制课程成绩 /// </summary> public override void BuildRestriction() { coures.Select( "201" , 95M); } /// <summary> /// 本科生选获得课程字典对象 /// </summary> /// <returns></returns> public override Coures GetCoures() { return coures; } } /// <summary> /// 研究生选课成绩 /// </summary> public class GraduateBuilder : Builder { private Coures coures = new Coures(); /// <summary> /// 研究生选必修课程成绩 /// </summary> public override void BuildCompulsory() { coures.Select( "S001" , 70M); } /// <summary> /// 研究生选选修课程成绩 /// </summary> public override void BuildElective() { coures.Select( "S101" , 75M); } /// <summary> /// 研究生选限制课程成绩 /// </summary> public override void BuildRestriction() { coures.Select( "S201" , 80M); } /// <summary> /// 研究生选获得课程字典对象 /// </summary> /// <returns></returns> public override Coures GetCoures() { return coures; } } /// <summary> /// 课程成绩管理类 /// </summary> public class CourseScoresManager { /// <summary> /// 这里的参数便是未确定的 /// </summary> /// <param name="builder"></param> public void CourseScoresManager(Builder builder) { builder.BuildCompulsory(); builder.BuildElective(); builder.BuildRestriction(); } } class Program { static void Main( string [] args) { /* Builder instance = new UndergraduateBuilder(); */ Builder instance = new GraduateBuilder(); CourseScoresManager courseScoresManager = new CourseScoresManager(instance); Coures coures = instance.GetCoures(); decimal totalScores = coures.ComputeScores(); Console.WriteLine(totalScores); Console.WriteLine( " " ); Console.ReadLine(); } } } |
四、使用场景
应用场景是当创建一个复杂的对象时,这个对象由各个子对象构成,而由于需求的变化导致子对象的性质也是未确定的。
我们一般为一个类提供构造函数,并利用这个构造函数完成对象的创建工作。当客户知道为哪个类创建实例,并知道构造函数的参数时(假设是用带参数的构造函数)。然而由于条件的现限制,是无法用通常的方式来构造对象的实例! 在进行对象构造之前,要逐步收集与构造相关的信息.那么创建对象的过程和对象的表现就应该分离开来。此时对象的表现是相对稳定的。