设计模式之创建型模式中的建造者模式(Builder Pattern)
基本介绍
建造者模式的四个角色
- 产品角色(Product):我们所要构建的产品对象;
- 抽象建造者(Builder):创建产品(Product)对象的接口 / 抽象类。它定义了创建一个产品(Product)对象所需要的各个部件的操作(抽象方法),同时包含一个获取产品(Product)对象(获取成品)的方法。
- 具体建造者(ConcreteBuilder):抽象建造者的具体实现,实现抽象建造者(Builder)的接口,构建和装配产品(Product)对象的各个部件,对于不同的部件或者构建步骤进行不同的详细实现,来完成不同的产品。
- 指导者(Director):主要用来使用 Buider 接口,构建一个使用 Buider 接口的对象,以一个相对稳定且统一的过程生产产品(Product)对象。
日常举例
建造小汽车的例子:小汽车主要部件:发动机(Engine)、车身框架(Frame)、轮胎(Wheel)等,不管是什么品牌的汽车,都有这些部件,只不过内部的构造和质量等不一样。代码实现,如下:
- 产品角色(Product)
1 | public class Car { |
- 抽象建造者(Builder)
1 | public interface CarBuilder { |
- 具体建造者(ConcreteBuilder)
1 | public class BaoMaCarBuilder implements CarBuilder{ |
- 指导者(Director)
1 | public class CarDirector { |
- 客户端使用
1 | public class Client { |
运行结果:
建造者模式在 JDK 中的应用
先看一张 StringBuilder 类图
源码:java.lang.Appendable1
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
71public interface Appendable {
/**
* Appends the specified character sequence to this <tt>Appendable</tt>.
*
* <p> Depending on which class implements the character sequence
* <tt>csq</tt>, the entire sequence may not be appended. For
* instance, if <tt>csq</tt> is a {@link java.nio.CharBuffer} then
* the subsequence to append is defined by the buffer's position and limit.
*
* @param csq
* The character sequence to append. If <tt>csq</tt> is
* <tt>null</tt>, then the four characters <tt>"null"</tt> are
* appended to this Appendable.
*
* @return A reference to this <tt>Appendable</tt>
*
* @throws IOException
* If an I/O error occurs
*/
Appendable append(CharSequence csq) throws IOException;
/**
* Appends a subsequence of the specified character sequence to this
* <tt>Appendable</tt>.
*
* <p> An invocation of this method of the form <tt>out.append(csq, start,
* end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in
* exactly the same way as the invocation
*
* <pre>
* out.append(csq.subSequence(start, end)) </pre>
*
* @param csq
* The character sequence from which a subsequence will be
* appended. If <tt>csq</tt> is <tt>null</tt>, then characters
* will be appended as if <tt>csq</tt> contained the four
* characters <tt>"null"</tt>.
*
* @param start
* The index of the first character in the subsequence
*
* @param end
* The index of the character following the last character in the
* subsequence
*
* @return A reference to this <tt>Appendable</tt>
*
* @throws IndexOutOfBoundsException
* If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
* is greater than <tt>end</tt>, or <tt>end</tt> is greater than
* <tt>csq.length()</tt>
*
* @throws IOException
* If an I/O error occurs
*/
Appendable append(CharSequence csq, int start, int end) throws IOException;
/**
* Appends the specified character to this <tt>Appendable</tt>.
*
* @param c
* The character to append
*
* @return A reference to this <tt>Appendable</tt>
*
* @throws IOException
* If an I/O error occurs
*/
Appendable append(char c) throws IOException;
}
源码:java.lang.AbstractStringBuilder(片段)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
40abstract class AbstractStringBuilder implements Appendable, CharSequence {
...
// Documentation in subclasses because of synchro difference
public AbstractStringBuilder append(StringBuffer sb) {
if (sb == null)
return appendNull();
int len = sb.length();
ensureCapacityInternal(count + len);
sb.getChars(0, len, value, count);
count += len;
return this;
}
/**
* @since 1.8
*/
AbstractStringBuilder append(AbstractStringBuilder asb) {
if (asb == null)
return appendNull();
int len = asb.length();
ensureCapacityInternal(count + len);
asb.getChars(0, len, value, count);
count += len;
return this;
}
// Documentation in subclasses because of synchro difference
public AbstractStringBuilder append(CharSequence s) {
if (s == null)
return appendNull();
if (s instanceof String)
return this.append((String)s);
if (s instanceof AbstractStringBuilder)
return this.append((AbstractStringBuilder)s);
return this.append(s, 0, s.length());
}
...
}
源码:java.lang.StringBuilder(片段)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
47public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
...
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
public StringBuilder append(String str) {
super.append(str);
return this;
}
/**
* Appends the specified {@code StringBuffer} to this sequence.
* <p>
* The characters of the {@code StringBuffer} argument are appended,
* in order, to this sequence, increasing the
* length of this sequence by the length of the argument.
* If {@code sb} is {@code null}, then the four characters
* {@code "null"} are appended to this sequence.
* <p>
* Let <i>n</i> be the length of this character sequence just prior to
* execution of the {@code append} method. Then the character at index
* <i>k</i> in the new character sequence is equal to the character at
* index <i>k</i> in the old character sequence, if <i>k</i> is less than
* <i>n</i>; otherwise, it is equal to the character at index <i>k-n</i>
* in the argument {@code sb}.
*
* @param sb the {@code StringBuffer} to append.
* @return a reference to this object.
*/
public StringBuilder append(StringBuffer sb) {
super.append(sb);
return this;
}
public StringBuilder append(CharSequence s) {
super.append(s);
return this;
}
...
}
分析: 接口 Appendable 定义了多个 append 抽象方法,即为抽象建造者;抽象类 AbstractStringBuilder 实现了接口 Appendable 的方法,即为具体建造者,但是不能实例化;StringBuilder 继承了抽象类 AbstractStringBuilder,具体的方法已经由 AbstractStringBuilder 实现,StringBuilder 对部分方法进行了覆盖,由此可以看出,StringBuilder 既充当了具体建造者,也是指导者的角色。
附:本次演示的项目地址
https://github.com/syshlang/java-design-patterns