美文网首页IT@程序员猿媛程序员
Java之Builder模式替代多参数构造器

Java之Builder模式替代多参数构造器

作者: 有财君 | 来源:发表于2019-04-27 22:54 被阅读2次

    虽然现在用Java可以说是得心应手,但是作为一门生态系统庞大,功能完备且在不断更新的语言,还是要没事就再学习一下的,也许在工作中积累的经验能帮助我理解以前学习的时候没有能理解的知识。

    《Effective Java》是一本很多人都推崇的书,事实也的确如此,最近一条一条的阅读,感觉受益良多。

    假设我有一个Car类,包括了不少属性,就像下面的代码一样:

    package com.example.demo;
    
    
    import com.google.common.base.Objects;
    
    import java.util.StringJoiner;
    
    public class Car {
        //价格
        private int price;
    
        //制造商
        private String producer;
    
        //颜色
        private String color;
    
        //制造年份
        private String produceYear;
    
        //是否四驱
        private boolean isFourWheelDrive;
        public Car() {
        }
        public Car(int price, String producer, String color, String produceYear, boolean isFourWheelDrive) {
            this.price = price;
            this.producer = producer;
            this.color = color;
            this.produceYear = produceYear;
            this.isFourWheelDrive = isFourWheelDrive;
        }
    
        public int getPrice() {
            return price;
        }
    
        public void setPrice(int price) {
            this.price = price;
        }
    
        public String getProducer() {
            return producer;
        }
    
        public void setProducer(String producer) {
            this.producer = producer;
        }
    
        public String getColor() {
            return color;
        }
    
        public void setColor(String color) {
            this.color = color;
        }
    
        public String getProduceYear() {
            return produceYear;
        }
    
        public void setProduceYear(String produceYear) {
            this.produceYear = produceYear;
        }
    
        public boolean isFourWheelDrive() {
            return isFourWheelDrive;
        }
    
        public void setFourWheelDrive(boolean fourWheelDrive) {
            isFourWheelDrive = fourWheelDrive;
        }
    
        @Override
        public String toString() {
            return new StringJoiner(", ", Car.class.getSimpleName() + "[", "]")
                    .add("price=" + price)
                    .add("producer='" + producer + "'")
                    .add("color='" + color + "'")
                    .add("produceYear='" + produceYear + "'")
                    .add("isFourWheelDrive=" + isFourWheelDrive)
                    .toString();
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Car car = (Car) o;
            return price == car.price &&
                    isFourWheelDrive == car.isFourWheelDrive &&
                    Objects.equal(producer, car.producer) &&
                    Objects.equal(color, car.color) &&
                    Objects.equal(produceYear, car.produceYear);
        }
    
        @Override
        public int hashCode() {
            return Objects.hashCode(price, producer, color, produceYear, isFourWheelDrive);
        }
    }
    

    又臭又长是不是?我也觉得,所以这个类可以用lombok优化一下,参考我以前写的文章:

    Java好用的工具之lombok

    跑题了,我这次想说的是我这个类写的很不好,不是因为没有用lombok,也不是因为写的又臭又长,而是因为我想new这个类的对象的时候,我发现构造器参数太多了,我不太能记得清楚顺序。

    所以为了简单一点,我还是用setter方法辅助我生成对象吧:

            Car car = new Car();
    
            car.setColor("black");
            car.setPrice(100000);
            car.setProducer("Wuling");
            car.setFourWheelDrive(false);
            car.setProduceYear("2019");
        }
    

    这还是好丑陋,而且《Effective Java》上还强调了一点,就是:

    由于构造过程被分到了多个调用中,一个JavaBean在其构造过程中可能处于不一致的状态。

    如果能够这样新建一个Car对象,那是多么的美好,像代码片段3:

            Car car = Car.builder().color("black")
                    .isFourWheelDrive(false)
                    .price(100000)
                    .producer("Wuling")
                    .produceYear("2019").build();
    

    为了实现这个目的,我们改一下Car的代码,代码片段4:

    package com.example.demo;
    
    
    public class Car {
        //价格
        private int price;
    
        //制造商
        private String producer;
    
        //颜色
        private String color;
    
        //制造年份
        private String produceYear;
    
        //是否四驱
        private boolean isFourWheelDrive;
    
        private Car(Builder builder) {
            this.price = builder.price;
            this.produceYear = builder.produceYear;
            this.color = builder.color;
            this.producer = builder.producer;
            this.isFourWheelDrive = builder.isFourWheelDrive;
        }
    
        public static class Builder {
            //价格
            private int price;
    
            //制造商
            private String producer;
    
            //颜色
            private String color;
    
            //制造年份
            private String produceYear;
    
            //是否四驱
            private boolean isFourWheelDrive;
    
            public Builder price(int price) {
                this.price = price;
                return this;
            }
    
            public Builder producer(String producer) {
                this.producer = producer;
                return this;
            }
    
            public Builder color(String color) {
                this.color = color;
                return this;
            }
    
            public Builder produceYear(String produceYear) {
                this.produceYear = produceYear;
                return this;
            }
    
            public Builder isFourWheelDrive(boolean isFourWheelDrive) {
                this.isFourWheelDrive = isFourWheelDrive;
                return this;
            }
    
    
            public Car build() {
                return new Car(this);
            }
        }
    
    }
    

    此时注意,这是按照《Effective Java》的写法写的,实际上创建对象的时候和上面的代码略有不同,代码片段5:

            Car car = new Car.Builder()
                    .color("black")
                    .price(100000)
                    .producer("Wuling")
                    .produceYear("2019").isFourWheelDrive(false)
                    .build();
    

    lombok有一个@Builder注解,也能实现builder模式,而且调用的时候,正是代码片段3写的那样。至于有什么不同,其实就是下面代码片段6:

    package com.example.demo;
    
    
    //@Builder
    public class Car {
        //价格
        private int price;
    
        //制造商
        private String producer;
    
        //颜色
        private String color;
    
        //制造年份
        private String produceYear;
        
        //是否四驱
        private boolean isFourWheelDrive;
    
        private Car(CarBuilder builder) {
            this.price = builder.price;
            this.produceYear = builder.produceYear;
            this.color = builder.color;
            this.producer = builder.producer;
            this.isFourWheelDrive = builder.isFourWheelDrive;
        }
        
        public static CarBuilder builder() {
            return new CarBuilder();
        } 
    
        public static class CarBuilder {
            //价格
            private int price;
    
            //制造商
            private String producer;
    
            //颜色
            private String color;
    
            //制造年份
            private String produceYear;
    
            //是否四驱
            private boolean isFourWheelDrive;
    
            public CarBuilder price(int price) {
                this.price = price;
                return this;
            }
    
            public CarBuilder producer(String producer) {
                this.producer = producer;
                return this;
            }
    
            public CarBuilder color(String color) {
                this.color = color;
                return this;
            }
    
            public CarBuilder produceYear(String produceYear) {
                this.produceYear = produceYear;
                return this;
            }
    
            public CarBuilder isFourWheelDrive(boolean isFourWheelDrive) {
                this.isFourWheelDrive = isFourWheelDrive;
                return this;
            }
    
            public Car build() {
                return new Car(this);
            }
        }
    
    }
    

    就是加上了一个静态工厂方法,但是这个设计,不就刚好契合了之前讲过的,用静态工厂方法替换构造器的基本思想吗?

    好了,这段代码还是又臭又长,虽然思想上了档次,但是代码还是那么的丑陋,这个时候还是请出lombok吧,此时的代码就变成了代码片段7:

    package com.example.demo;
    
    import lombok.Builder;
    
    @Builder
    public class Car {
        //价格
        private int price;
    
        //制造商
        private String producer;
    
        //颜色
        private String color;
    
        //制造年份
        private String produceYear;
    
        //是否四驱
        private boolean isFourWheelDrive;
    }
    

    看看,只要20多行就完成了前面的所有操作,还不赶快用lombok!!!

    相关文章

      网友评论

        本文标题:Java之Builder模式替代多参数构造器

        本文链接:https://www.haomeiwen.com/subject/quvlnqtx.html