设计模式之创建者模式
一、定义说明
建造者模式(Builder Pattern)也叫做生成器模式,其定义如下:Separate the construction of a complex object from its representation so that the same construction process can create different representations.(将一个复杂对象的构建与它的表示分
离,使得同样的构建过程可以创建不同的表示。)
下图为构建者模式的类图
成员分析:
Director:控制者类,这是控制整个组合过程,在这个类内部有个Construct()方法,这个方法的作用就是通过调用Builder内部的各个组件的生成方法来完成组装;
Builder:构建者接口,定义各部件生成的方法;
ConcreteBuilder:具体构建者类:实现Builder构建者接口,具体定义如何生成各个部件;依赖于Product成品类,其中还有获取成品组装结构的方法GetResult()方法;
Product:成品类
二、实例分析
Builder角色:
//抽象类,定义所有的生成product的组件的方法入口
public abstract class Builder {
public abstract void buildPart1();
public abstract void buildPart2();
public abstract void buildPart3();
}
Director角色:
// 将一个复杂的构建过程与其表示相分离
public class Director {
private Builder builder; // 针对接口编程,而不是针对实现编程
public Director(Builder builder) {
this.builder = builder;
}
public void setBuilder(Builder builder) {
this.builder = builder;
}
// 控制(定义)一个复杂的构建过程,自由调整各个组件之间的顺序或者关系等
public void construct() {
builder.buildPart1();
for (int i = 0; i < 5; i++) {
builder.buildPart2();
}
builder.buildPart3();
}
}
ConcreteBuilder角色:
/**
* 此处实现了建造纯文本文档的具体建造者。
* 重写父类的中的创建方法,按照自己的方式进行构建每个组件
* 可以考虑再实现一个建造HTML文档、XML文档,或者其它什么文档的具体建造者。
* 这样,就可以使得同样的构建过程可以创建不同的表示
*/
public class ConcreteBuilder1 extends Builder {
private StringBuffer buffer = new StringBuffer();//假设 buffer.toString() 就是最终生成的产品
@Override
public void buildPart1() {//实现构建最终实例需要的所有方法
buffer.append("Builder1 : Part1\n");
}
@Override
public void buildPart2() {
buffer.append("Builder1 : Part2\n");
}
@Override
public void buildPart3() {
buffer.append("Builder1 : Part3\n");
}
public String getResult() {//定义获取最终生成实例的方法
return buffer.toString();
}
}
测试类:
public class Client {
public void testBuilderPattern() {
ConcreteBuilder1 b1 = new ConcreteBuilder1();//建造者
Director director = new Director(b1);//控制者
director.construct();//控制者调用构建方法,由建造者进行具体的构建
String result = b1.getResult();//获取最终生成结果
System.out.printf("the result is :%n%s", result);
}
}
三、构建者模式的应用
1、优点:
- 良好的封装性:使用构建者模式不用关心产品内部的实现细节,直接调用使用控制者调用具体的建造者即可
- 易于扩展:建造者是独立的,所以具有良好的扩展性,上面的例子中,完全可以增加ConcreteBuilder12来对程序进行扩展
- 便于控制风险:核心是建造者,而且建造者又是独立的,所以修改建造者不会对其他模块产生影响
2、使用场景:
- 相同的方法,不同的执行顺序,从而产生了不同的结果事件(主要是针对一个对象中的组件关系进行使用)
- 当一个对象比较复杂并且容易出错时候,可以考虑这种模式去屏蔽创造细节。
3、注意事项:
工厂模式和构建者模式的区别:他们都是属于创建类模式,但是侧重点不同,构建者模式更加注重对象的组件类型和装配顺序,在创建对象的过程中,对象组件是已经常见好的;而工厂模式则是创建对象的每个组件,最后返回整体,创建组件是它所关注的。
4、实践:
1)、Mybatis中的SqlSessionFactoryBuilder,其中重载了大量的builder方法,根据参数的不同创建出SqlSessionFactory对象,使用者只需要传递具体参数而不用关系内部是如何创建出需要的对象的。
其中最重要的是 XMLConfigBuilder
的 parse
方法,代码如下 :
parse
方法最终要返回一个 Configuration
对象,构建 Configuration
对象的建造过程都在 parseConfiguration
方法中,这也就是 Mybatis
解析 XML配置文件
来构建 Configuration
对象的主要过程
所以 XMLConfigBuilder
是建造者 SqlSessionFactoryBuilder
中的建造者,复杂产品对象分别是 SqlSessionFactory
和 Configuration
2)、java.lang.StringBuilder 中的建造者模式
StringBuilder的继承关系,如下图所示:
Appenable接口如下:
public interface Appendable {
Appendable append(CharSequence csq) throws IOException;
Appendable append(CharSequence csq, int start, int end) throws IOException;
Appendable append(char c) throws IOException;
}
StringBuilder
的父类 AbstractStringBuilder
实现了 Appendable
接口
abstract class AbstractStringBuilder implements Appendable, CharSequence {
char[] value;
int count;
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
// ...省略...
}
Stringbuilder:
public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence {
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
// ...省略...
}
我们可以看出,Appendable
为抽象建造者,定义了建造方法,StringBuilder
既充当指挥者角色,又充当产品角色,又充当具体建造者,建造方法的实现由 AbstractStringBuilder
完成,而 StringBuilder
继承了 AbstractStringBuilder
参考文章: