实例化对象除了构造器还有构建器

采用构建器模式可以更优雅的创建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对象内部具体的信息了,这就是采用构建器带来的好处。

本博客采用 知识共享署名-禁止演绎 4.0 国际许可协议 进行许可

本文标题:实例化对象除了构造器还有构建器

本文地址:https://jizhong.plus/post/2020/04/java-builder.html