原创

Builder建造者设计模式

Builder建造者设计模式

使用场景:创建实体类对象

  • 类的属性太多。一般大于等于4个属性时,可以考虑使用建造者模式;
  • 类的属性为可选择属性(Optional parameters)。为什么一般要求属性是可选择性的,因为如果是必需属性(Required parameters),在进行手动构造对象参数时,可能会遗漏,导致对象生成失败;

使用案例一

Computer类:

public class Computer {
    private final String material;
    private final String cpu;
    private final String ram;
    private final String monitor;
    private final double price;
    private final String brand;
    private final String mouse;
    private final String keyboard;
    private final Set<String> software;

    public static class Builder{
        // Required parameter
        private final String material;
        // Optional parameters
        private String cpu;
        private String ram;
        private String monitor;
        private double price;
        private String brand;
        private String mouse;
        private String keyboard;
        private final Set<String> software = new HashSet<>();

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

        public Builder cpu(String cpuIn) {
            cpu = cpuIn;
            return this;
        }

        public Builder ram(String ramIn) {
            ram = ramIn;
            return this;
        }

        public Builder monitor(String monitorIn) {
            monitor = monitorIn;
            return this;
        }

        public Builder price(double priceIn) {
            price = priceIn;
            return this;
        }

        public Builder brand(String brandIn) {
            brand = brandIn;
            return this;
        }

        public Builder mouse(String mouseIn) {
            mouse = mouseIn;
            return this;
        }

        public Builder keyboard(String keyboardIn) {
            keyboard = keyboardIn;
            return this;
        }

        public Builder software(String softwareIn) {
            software.add(softwareIn);
            return this;
        }

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

    private Computer(Builder builder) {
        material = builder.material;
        cpu = builder.cpu;
        ram = builder.ram;
        monitor = builder.monitor;
        price = builder.price;
        brand = builder.brand;
        mouse = builder.mouse;
        keyboard = builder.keyboard;
        software = builder.software;
    }

    @Override
    public String toString() {
        return "Computer{" +
                "made with: '" + material + '\'' +
                ", cpu='" + cpu + '\'' +
                ", ram='" + ram + '\'' +
                ", monitor='" + monitor + '\'' +
                ", price=" + price +
                ", brand='" + brand + '\'' +
                ", mouse='" + mouse + '\'' +
                ", keyboard='" + keyboard + '\'' +
                ", software=" + software.toString() +
                '}';
    }
}

Unit Test:

@Test
public void test_builderPattern() {
    Computer computer = new Computer.Builder("silicon").cpu("CORE i7").ram("16GB").brand("HP").keyboard("Keyboard").monitor("Lenovo").mouse("Logic").price(9999.99)
            .software("WPS").software("MS Office").software("IDEA").software("SQL Server").build();
    System.out.println(computer.toString());
}

结果:

Computer{made with: 'silicon', cpu='CORE i7', ram='16GB', monitor='Lenovo', price=9999.99, brand='HP', mouse='Logic', keyboard='Keyboard', software=[IDEA, WPS, SQL Server, MS Office]}

使用案例二:类继承中的建造者模式

Family 抽象类:

public abstract class Family {
    private final String house;
    private final String me;
    public enum FamilyMember {MOTHER, FATHER, GRANDPA, GRANDMA, SISTER, BROTHER};
    private final Set<FamilyMember> familyMembers;

    public abstract static class Builder<T extends Builder<T>> {
        private final String house;
        private final String me;
        private final EnumSet<FamilyMember> familyMembers = EnumSet.noneOf(FamilyMember.class);

        public Builder(String name){
            house = name + "'s Family";
            me = name;
        }

        public T addFamilyMember(FamilyMember familyMember) {
            familyMembers.add(Objects.requireNonNull(familyMember));
            return self();
        }

        abstract Family build();

        protected abstract T self();
    }

    public Family(Builder<?> builder) {
        house = builder.house;
        me = builder.me;
        familyMembers = builder.familyMembers.clone();
    }

    public Set<FamilyMember> getFamilyMembers() {
        return familyMembers;
    }

    public String getHouse() {
        return house;
    }

    public String getMe() {
        return me;
    }

    public String introduceInfo() {
        return "My name is " + me + ". This is " + house + ".";
    }

    @Override
    public String toString() {
        return "Family{" +
                "house='" + house + '\'' +
                ", me='" + me + '\'' +
                ", familyMembers=" + familyMembers.toString() +
                '}';
    }
}

实体类CoCoFamily:

public class CoCoFamily extends Family{
    private final String cocoName;
    private final String cocoGender;

    private CoCoFamily(Builder builder) {
        super(builder);
        cocoGender = "male";
        cocoName = "CoCo";
    }

    public static class Builder extends Family.Builder<Builder> {

        public Builder(String name) {
            super(name);
        }

        @Override
        public CoCoFamily build() {
            return new CoCoFamily(this);
        }

        @Override
        protected Builder self() {
            return this;
        }
    }

    @Override
    public String toString() {
        return super.introduceInfo() +
                " CoCoFamily{" +
                "cocoName='" + cocoName + '\'' +
                ", cocoGender='" + cocoGender + '\'' +
                ", cocoFamilyMembers='" + super.getFamilyMembers().toString() + '\'' +
                '}';
    }
}

Unit Test:

@Test
public void test_hierarchyBuilderPatter() {
    CoCoFamily cocoFamily = new CoCoFamily.Builder("CoCo").addFamilyMember(Family.FamilyMember.MOTHER).addFamilyMember(Family.FamilyMember.FATHER).build();
    System.out.println(cocoFamily.toString());
}

结果:

My name is CoCo. This is CoCo's Family. CoCoFamily{cocoName='CoCo', cocoGender='male', cocoFamilyMembers='[MOTHER, FATHER]'}

建造者模式特点

优点

  • 创建对象灵活;
  • 可多次调用同一个属性set方法,为某个属性初始化添加多个值,如上面例子中的 private final Set<String> software = new HashSet<>();

缺点

  • 比堆叠式构造方法创建类对象啰嗦一点,但同时也规避了堆叠式构造器创建类对象参数混乱的问题;
  • 由于使用建造者模式时,每次创建类对象都会先创建一个Builder对象,这增加了内存消耗;
  • 当从使用传统构造器创建类对象或使用工厂模式创建类对象转变到建造者模式时,大量的类属性将会成为重构的麻烦点。
Java
  • 作者:CoCo(联系作者)
  • 发表时间:2024-03-28 19:06:06
  • 更新时间:2024-03-28 19:06:06
  • 版权声明 © 原创不易,转载请注明出处
  • 留言