生成器模式(Builder)是使用多个“小型”工厂来最终创建出一个完整对象。
当我们使用Builder的时候,一般来说,是因为创建这个对象的步骤比较多,每个步骤都需要一个零部件,最终组合成一个完整的对象。
我们仍然以Markdown转HTML为例,因为直接编写一个完整的转换器比较困难,但如果针对类似下面的一行文本:
转换成HTML就很简单:
- 如果以
#
开头,使用HeadingBuilder
转换; - 如果以
>
开头,使用QuoteBuilder
转换; - 如果以
—-
开头,使用HrBuilder
转换;
这个HtmlBuilder
写出来如下:
注意观察上述代码,HtmlBuilder
并不是一次性把整个Markdown转换为HTML,而是一行一行转换,并且,它自己并不会将某一行转换为特定的HTML,而是根据特性把每一行都“委托”给一个去转换,最后,把所有转换的结果组合起来,返回给客户端。
这样一来,我们只需要针对每一种类型编写不同的Builder。例如,针对以#
开头的行,需要HeadingBuilder
:
public class HeadingBuilder {
public String buildHeading(String line) {
int n = 0;
while (line.charAt(0) == '#') {
n++;
line = line.substring(1);
}
}
}
注意:实际解析Markdown是带有状态的,即下一行的语义可能与上一行相关。这里我们简化了语法,把每一行视为可以独立转换。
JavaMail的MimeMessage
就可以看作是一个Builder模式,只不过Builder和最终产品合二为一,都是MimeMessage
:
很多时候,我们可以简化Builder模式,以链式调用的方式来创建对象。例如,我们经常编写这样的代码:
StringBuilder builder = new StringBuilder();
builder.append(secure ? "https://" : "http://")
.append("www.liaoxuefeng.com")
.append("/")
.append("?t=0");
由于我们经常需要构造URL字符串,可以使用Builder模式编写一个URLBuilder,调用方式如下:
从下载练习:使用Builder模式实现一个URLBuilder (推荐使用快速下载)