采用构建器模式可以更优雅的创建Java对象。先看下面这段代码,了解不使用构建器带来的麻烦,后面再使用构建器优化它。
package com.javafm.builder;
public class Car {
// 发动机编码
private final String engineCode;
// 长 可选
private final int length;
// 宽 可选
private final int width;
// 高 可选
private final int height;
// 座位数 可选
private final int seat;
// 颜色 可选
private final String color;
public Car(String engineCode) {
this(engineCode, 0, 0, 0, 0, null);
}
public Car(String engineCode, int length) {
this(engineCode, length, 0, 0, 0, null);
}
public Car(String engineCode, int length, int width) {
this(engineCode, length, width, 0, 0, null);
}
public Car(String engineCode, int length, int width, int height) {
this(engineCode, length, width, height, 0, null);
}
public Car(String engineCode, int length, int width, int height, int seat) {
this(engineCode, length, width, height, seat, null);
}
public Car(String engineCode, int length, int width, int height, int seat, String color) {
this.engineCode = engineCode;
this.length = length;
this.width = width;
this.height = height;
this.seat = seat;
this.color = color;
}
public String getEngineCode() {
return engineCode;
}
public int getLength() {
return length;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public int getSeat() {
return seat;
}
public String getColor() {
return color;
}
}
从代码看我们有一个Car类,Car对象一旦创建内部信息是不可变的,因此除了构造函数外,无法使用set方式来设置内部的信息。那么问题来了,当内部信息存在多个可选不可变信息参数时,就需要多个不同的构造函数。当使用者采用构造函数了实例化对象的时候,往往因为参数过多,方法过多把人整懵逼。你看下面这段代码,就会深有体会了。
package com.javafm.builder;
public class Test {
public static void main(String[] args) {
// 只有发动机编号的car对象
Car car = new Car("abc123");
// 有发动机编号、长度的car对象
Car car1 = new Car("abc123", 11);
// 有发动机编号、长度、宽度的car对象
Car car2 = new Car("abc123", 11, 2);
// 有发动机编号、长度、宽度、高度的car对象
Car car3 = new Car("abc123", 11, 2, 1);
// 有发动机编号、长度、宽度、高度、座位数的car对象
Car car4 = new Car("abc123", 11, 2, 1, 5);
// 有发动机编号、长度、宽度、高度、座位数、颜色的car对象
Car car5 = new Car("abc123", 11, 2, 1, 5, "红色");
}
}
一眼看去,要不是有注释,完全不知道构造函数里每一个参数对应的是什么。 那么是否有更优雅的写法呢?必须有的,那就是采用构建器模式,即Builder。
优化Car类的代码,加入构建器。优化后的代码如下:
package com.javafm.builder;
public class Car {
// 发动机编码
private final String engineCode;
// 长 可选
private final int length;
// 宽 可选
private final int width;
// 高 可选
private final int height;
// 座位数 可选
private final int seat;
// 颜色 可选
private final String color;
public Car(CarBuilder builder) {
this.engineCode = builder.engineCode;
this.length = builder.length;
this.width = builder.width;
this.height = builder.height;
this.seat = builder.seat;
this.color = builder.color;
}
public static class CarBuilder {
// 发动机编码
private String engineCode;
// 长 可选
private int length;
// 宽 可选
private int width;
// 高 可选
private int height;
// 座位数 可选
private int seat;
// 颜色 可选
private String color;
public CarBuilder(String engineCode) {
this.engineCode = engineCode;
}
public CarBuilder length(int length) {
this.length = length;
return this;
}
public CarBuilder width(int width) {
this.width = width;
return this;
}
public CarBuilder height(int height) {
this.height = height;
return this;
}
public CarBuilder seat(int seat) {
this.seat = seat;
return this;
}
public CarBuilder color(String color) {
this.color = color;
return this;
}
public Car build() {
return new Car(this);
}
}
public String getEngineCode() {
return engineCode;
}
public int getLength() {
return length;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public int getSeat() {
return seat;
}
public String getColor() {
return color;
}
}
从优化后的代码看到,增加了一个CarBuilder静态内部内。CarBuilder构造函数的参数为必填参数engineCode,其它可选参数做成一个个的方法,然后在Car的构造函数中传入CarBuilder作为参数来初始化对象内部信息,最后在静态内部类CarBuild中有一个build()函数,在里面实例化Car对象。
测试调用代码如下:
package com.javafm.builder;
public class Test {
public static void main(String[] args) {
Car car = new Car.CarBuilder("abc123").build();
Car car1 = new Car.CarBuilder("abc123").length(11).build();
Car car2 = new Car.CarBuilder("abc123").length(11).width(2).build();
Car car3 = new Car.CarBuilder("abc123").length(11).width(2).height(1).build();
Car car4 = new Car.CarBuilder("abc123").length(11).width(2).height(1).seat(5).build();
Car car5 = new Car.CarBuilder("abc123").length(11).width(2).height(1).seat(5).color("红色").build();
}
}
从这个Test代码与之前对比,是不是不用注释也能很清楚的知道Car对象内部具体的信息了,这就是采用构建器带来的好处。