建造者模式

Posted by New Boy on March 15, 2018

前言

在设计模式的分类中,建造者模式属于创建型模式,建造者模式主要由两种应用场景。

第一种应用场景

首先,适用于一些复杂对象的构建。就拿造房子来说,一个房子要建造起来,就要确定房子的长、宽、高、预算等,这些参数也取决于我是要建造一个大房子还是小房子,正常的方法可能就是new一个,通过构造器赋值,或者通过setter赋值。用建造者模式则是这样的

House:

//省略了set,get等 
public class House {
    private Integer height;
    private Integer width;
    private Integer length;
    private Integer price;
}

Builder:

public interface Builder {
    void buildLength();
    void buildWidth();
    void buildHeight();
    void buildPrice();
    House getHouse();
}

如果说要建一所大房子,那么就需要一个类去继承Builder接口,完成里面一些参数的赋值

public class BigHouseBuilder implements Builder {
    private House house = new House();
    @Override
    public void buildLength() {
        house.setLength(100);
    }
    @Override
    public void buildWidth() {
        house.setWidth(100);
    }
    @Override
    public void buildHeight() {
        house.setHeight(100);
    }
    @Override
    public void buildPrice() {
        house.setPrice(1000000);
    }
    @Override
    public House getHouse() {
        return house;
    }
}

建造前的准备工作做好了,那不是需要建筑工人们施工去完成建造吗?

public class Workers {
    private Builder builder;

    public Workers(Builder builder) {
        this.builder = builder;
    }

    public House build() {
        builder.buildHeight();
        builder.buildLength();
        builder.buildWidth();
        builder.buildPrice();
        return builder.getHouse();
    }
}

测试类:

public class mainTest {
    public static void main(String[] args) {
        BigHouseBuilder builder = new BigHouseBuilder();
        Workers workers = new Workers(builder);
        House house = workers.build();
        System.out.println(house.toString());
    }
}

这时候主程序代码就很直观,很简洁。

同属于创建型模式,建造者模式和抽象工厂模式还是很像的,不过两者还是有一定区别,抽象工厂模式中往往一个函数就可以创建一个对象,而建造者模式则是创建单个对象。

第二种场景

对于第二种场景,网上一些比较浅的文章中没有提到。设计模式这东西学了一段时间,其实看看还是很简单的,但重要的还是一个实践的过程(好像整个计算机相关的知识都是这样,看看理论知识不难,代码实现起来就不是这么一回事了,所以自己也写例子,写博文,希望能早日参透)。回过神来,来讲讲第二种场景,主要用于javabean中,如果说一个javabean中有很多的属性,而且不是所有的属性都是必须的,那么再使用构造器的方式就很容易出错,一旦某两个参数的位置写反了,那么问题就大了。如果使用setter的方法,代码也是十分臃肿,不利于维护。就拿学生信息来举个例子吧,现在我们有学生的一些基本信息(姓名,学号之类),以及他某一学期的成绩,如果说要把这些信息存入同一个对象中,代码应该是这样的:

Base(成绩)(省略了get和set)

public class Base {
    private Integer chinese;
    private Integer maths;
    private Integer english;
}

基本信息Student

public class Student {
    private String name;
    private String id;
}

目标类StudentInfo

public class StudentInfo {
    private String name;
    private String id;
    private Integer chinese;
    private Integer maths;
    private Integer english;
    public static class Builder {
        private String name;
        private String id;
        private Integer chinese;
        private Integer maths;
        private Integer english;

        public Builder base(Base base) {
            this.chinese = base.getChinese();
            this.english = base.getEnglish();
            this.maths = base.getMaths();
            return this;
        }

        public Builder student(Student student) {
            this.id = student.getId();
            this.name = student.getName();
            return this;
        }

        public StudentInfo build() {
            StringBuffer stringBuffer = new StringBuffer();
            return new StudentInfo(this);
        }
    }
    private StudentInfo(Builder builder) {
        this.name = builder.name;
        this.chinese = builder.chinese;
        this.english = builder.english;
        this.maths = builder.maths;
        this.id = builder.id;
        this.name = builder.name;
    }
}

目标类中还是需要注意的,对StudentInfo类的构造函数进行了私有化,通过内部静态类Builder的build()去调用构造函数。

测试类:

public static void main(String[] args) {
        Student student = new Student("dmc", "1001");
        Base base = new Base(50, 150, 100);
        StudentInfo studentInfo = new StudentInfo.Builder()
                .student(student)
                .base(base)
                .build();
        System.out.println(studentInfo.toString());
}