设计模式——建造者模式

建造者模式

  • 建造者模式是什么?
  • 建造者模式解决什么问题
  • javabean
  • 建造者模式实现
  • 扩展——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);

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

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

建造者模式实现

采用构建器模式,并不直接生成想要的实例,而是先构造一个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和继承

Builder模式同样也可用于继承结构中,如下是奶茶抽象类

  • 利用enum规定配料,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,设计模式,建造者模式)