最近在看设计模式之禅。该书以生动有趣的言语为我们描绘了GoF所带来的设计模式的殿堂。其中有些设计模式讲的比较好,比如抽象工厂,模板方法等。
但是在将Builder模式的时候,个人感觉和自己的理解可能有些出入,所以在此记录下自己的理解。
Builder模式的wiki地址:
wiki - Builder pattern
说个题外话,设计模式的wiki有着非常详细的内容,有兴趣的可以去学习学习,这个是设计模式的首页:
Design Pattern
对于Builder方式来讲,常用于配置对象中,比如HttpClient的Config.class等。这是由于对于这种配置对象来讲,属性项较多。而对于属性较多的对象来讲,一般还可以采用setter来进行,这样也能合理避开构造函数由于属性增多而导致的爆炸性增长。而采用Java Bean setter的这种方式的不利是由于是先new出的对象,所以在setter的过程中,可能存在中间状态,这样在多线程的状态下可能会产生问题。
由此Builder的设计模式便应运而生。Builder模式的核心是,私有化构造函数,但是提供一个静态生成Builder对象的静态方法,该对象具有和构造的对象完全相同的属性,并且具有各种setter的方法,并且采用了流式的设计,也就是setter方法返回的是自己,这样就能够将set的方法连起来,最后,当所有的属性都已经赋值完毕后,可以纸巾采用build()方法,生成对象。
我们来看一下代码,以下的代码采用了两种方式,其中第一种是我们比较熟悉的,在Effective Java中我们也有了解,而第二种则是采用Java8新特性的,也是wiki的页面中示例所提供的方法:
// Car对象
public class Car {
// 名称
private String name;
// 拍照
private String no;
private Car(String no, String name) {
this.name = name;
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNo() {
return no;
}
public void setNo(String no) {
this.no = no;
}
// 返回Builder
public static CarBuilder getBuilder () {
return new CarBuilder();
}
// 返回Builder2
public static CarBuilder2 getBuilder2() {
return new CarBuilder2(Car::new);
}
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
", no='" + no + '\'' +
'}';
}
// 定义建造者,建造者的属性应该和car保持一致
public static class CarBuilder {
private String name;
private String no;
public CarBuilder() {
}
public CarBuilder setName(String name) {
this.name = name;
return this;
}
public CarBuilder setNo(String no) {
this.no = no;
return this;
}
public Car build() {
return new Car(this.no, this.name);
}
}
}
// 第二种Builder方式
public class CarBuilder2 {
private BiFunction<String, String, Car> builder;
private String name;
private String no;
public CarBuilder2(BiFunction<String,String,Car> builder) {
this.builder = builder;
}
public String getName() {
return name;
}
public CarBuilder2 setName(String name) {
this.name = name;
return this;
}
public String getNo() {
return no;
}
public CarBuilder2 setNo(String no) {
this.no = no;
return this;
}
public Car build() {
return builder.apply(no, name);
}
}
测试类
public class BuilderTest {
@Test
public void testCarBuilder() {
Car.CarBuilder builder = Car.getBuilder();
builder.setName("Buck").setNo("京A52450");
Car car = builder.build();
Assert.assertEquals(car.getName(), "Buck");
Assert.assertEquals(car.getNo(), "京A52450");
}
@Test
public void testCarBuilder2() {
CarBuilder2 builder2 = Car.getBuilder2();
builder2.setName("Buck").setNo("京A52450");
Car car = builder2.build();
Assert.assertEquals(car.getName(), "Buck");
Assert.assertEquals(car.getNo(), "京A52450");
}
}