Java中级——利用构建器模式代替多参构造器

利用构建器模式代替多参构造器

  • 构造器和构建器模式是什么?
  • 问题引入
  • 解决方案1——javabean
  • 解决方案2——Builder
  • 扩展——Builder和继承

构造器和构建器模式是什么?

  • 构造器即构造函数,用于生成类实例
  • 构建器模式即 Builder 设计模式,也是用于生成类的实例

问题引入

当一个类具有多个可选域时(如对于Person,名字是必须的,其他可选),会出现多个重叠构造器,如下

class Person {
    private String name;
    private int age;
    private int height;
    private int weight;

    public Person(String name) {
        this(name, 0);
    }

    public Person(String name, int age) {
        this(name, age, 0);
    }

    public Person(String name, int age, int height) {
        this(name, age, height, 0);
    }

    public Person(String name, int age, int height, int weight) {
        this.name = name;
        this.age = age;
        this.height = height;
        this.weight = weight;
    }
}

当想创建实例时,需要不得不对本不需要设置的域设置值,如下只想对name、height和weight赋值,但不得不对age也赋值

Person person = new Person("song", 0, 170, 52);

与此同时,当域数量增多时,需要仔细查看每一个域的位置和用途,以避免错误的设置顺序

解决方案1——javabean

利用javabean,可先用无参构造器生成空对象,再用setter方法来为需要的参数赋值

class Person {
    private String name;
    private int age;
    private int height;
    private int weight;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }
}

创建实例

Person person = new Person();
person.setName("song");
person.setHeight(170);
person.setWeight(52);

javabean将类的构造过程分成了多个步骤,在构造过程中对象的状态可能处于不一致的状态,即并发修改,为避免出现这样的情况,需要额外的加锁操作

解决方案2——Builder

采用构建器模式,并不直接生成想要的实例,而是先构造一个Builder,利用Builder来为所需的参数赋值,最后再设置到实例中去

class Person {
    private String name;
    private int age;
    private int height;
    private int weight;

    public Person(Builder builder) {
        this.name = builder.name;
        this.age = builder.age;
        this.height = builder.height;
        this.weight = builder.weight;
    }

    public static class Builder {
        private String name;
        private int age = 0;
        private int height = 0;
        private int weight = 0;

        public Builder(String name) {
            this.name = name;
        }

        public Builder age(int age) {
            this.age = age;
            return this;
        }

        public Builder height(int height) {
            this.height = height;
            return this;
        }

        public Builder weight(int weight) {
            this.weight = weight;
            return this;
        }

        public Person build() {
            return new Person(this);
        }
    }
}

创建实例

Person person = new Person.Builder("song").height(170).weight(52).build();

利用Builder可单独为每个参数赋值,从而实现可选参数的设定

扩展——Builder和继承

如下是奶茶抽象类

  • 利用enmu规定配料,Set记录添加的配料

  • EnumSet记录Builder添加的配料

  • addTopping()添加配料返回Builder

  • build()和self()为抽象类由子类实现

    abstract class MilkTea {
    public enum Topping {Pudding, Pearl, Sago}

    private final Set toppings;
    
    abstract static class Builder> {
        private EnumSet toppings = EnumSet.noneOf(Topping.class);
    
        public T addTopping(Topping topping) {
            toppings.add(topping);
            return self();
        }
    
        abstract MilkTea build();
    
        protected abstract T self();
    }
    
    MilkTea(Builder builder) {
        toppings = builder.toppings.clone();
    }
    

    }

如下是其实现类

  • 利用enmu规定大小

  • 重写父类的build()和self()返回自身的实例和Builder

    class GreenTea extends MilkTea {
    public enum Size {Small, Medium, Large}

    private final Size size;
    
    public static class Builder extends MilkTea.Builder {
        private final Size size;
    
        public Builder(Size size) {
            this.size = size;
        }
    
        @Override
        GreenTea build() {
            return new GreenTea(this);
        }
    
        @Override
        protected Builder self() {
            return this;
        }
    }
    
    private GreenTea(Builder builder) {
        super(builder);
        size = builder.size;
    }
    

    }

创建实例

GreenTea greenTea = new GreenTea.Builder(GreenTea.Size.Small).addTopping(MilkTea.Topping.Pudding).addTopping(MilkTea.Topping.Pearl).build();

你可能感兴趣的:(java,后端,java,后端)