【设计模式】1分钟整明白什么是Builder建造者模式

663 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情 >>

场景切入

我们常常能碰到一个对象有非常多属性的时候,比如一个雇员信息,包括姓名,年龄,性别,住址,级别,身高,体重,身份证号,社保福利,绩效...等等字段,有时候我们需要得到部分字段的信息,也有可能需要获取全部字段信息,如果一个字段一个字段的set,那是相当繁琐的!!!

代码解决

针对如上情况,该怎么简化如此繁琐的工作呢?别急,builder 模式来帮忙!

直接上代码看效果:

public class Employee {
    private String name;
    private Integer age;
    private String sex;
    private Integer height;
    private Integer weight;
    private String address;
    private String level;
    //...还有很多属性

    //私有的构造方法
    private Employee(){

    }

    public static class EmployeeBuilder{
        Employee employee = new Employee();

        public EmployeeBuilder basicInfo(String name, Integer age, String sex){
            employee.name = name;
            employee.age = age;
            employee.sex = sex;
            return this;
        }

        public EmployeeBuilder height(Integer height){
            employee.height = height;
            return this;
        }

        public EmployeeBuilder weight(Integer weight){
            employee.weight = weight;
            return this;
        }

        public EmployeeBuilder address(String address){
            employee.address = address;
            return this;
        }

        public EmployeeBuilder level(String level){
            employee.level = level;
            return this;
        }

        public Employee build(){
            return employee;
        }
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                ", height=" + height +
                ", weight=" + weight +
                ", address='" + address + '\'' +
                ", level='" + level + '\'' +
                '}';
    }
}

我在Employee类中定义了一个静态内部类 EmployeeBuilder ,负责将 Employee 类的字段拆分,静态内部类每个方法都负责给相应的字段赋值,最后定义一个 build() 方法来返回我们需要的 Employee 对象。

来看调用:

public static void main(String[] args) {
    Employee e = new Employee.EmployeeBuilder()
            .basicInfo("张三", 18, "男")
            .height(178)
            .weight(65)
            //.level("初级")
            .build();
    System.out.println(e);
}

需要构造什么字段,直接在 new Employee.EmployeeBuilder() 后面 . 什么方法就行了,这是经典的链式编程 的方式,每个方法返回对象本身就可以实现。

builder模式

本例中代码实现就是用了 builder 的设计模式,通过 builder 模式我们很容易就能构造像 Employee 这样很复杂的对象。

builder设计模式就是用来 构造复杂对象 的,其特点:

  • 分离复杂对象的构建和表示
  • 同样的构建过程可以创建不同的表示

其实,我们在工作中自然而然的就会使用这种模式,我们无须对模式的概念啊,定义啊进行特别的记忆,用的时候自然实用,水到渠成。

比如,

StringBuilder sb = new StringBuilder();
sb.append("下蛋公鸡").append(",").append("公鸡中的战斗鸡!");
System.out.println(sb.toString());

还有 StringBuffer 也可以这样用,我们来看一下源码:

StringBuilder

public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{

    //...略

    //append()方法返回对象本身,这样在append一次之后还能接着直接.append()的方式调用。    
    @Override
    public StringBuilder append(Object obj) {
        return append(String.valueOf(obj));
    }

    @Override
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }
    //...
}

append() 方法返回对象本身,这样在 append 一次之后还能接着直接 .append() 的方式调用。 这其实就是 建造者模式 的体现,可以一部分一部分的建造对象,根据实际需要来调用 append() 方法。

StringBuffer

public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{
    //...

    //方法和StringBuilder的append实现方式是一样的(他们都继承了AbstractStringBuilder类)
    @Override
    public synchronized StringBuffer append(Object obj) {
        toStringCache = null;
        super.append(String.valueOf(obj));
        return this;
    }

    @Override
    public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }
    //...
}

StringBufferappend() 方法和 StringBuilderappend() 方法实现方式是一样的——他们都继承了AbstractStringBuilder类,只不过方法加了 synchronized 关键字,是线程安全的。

他们的父类 AbstractStringBuilder

abstract class AbstractStringBuilder implements Appendable, CharSequence {
    //...
    
    public AbstractStringBuilder append(Object obj) {
        return append(String.valueOf(obj));
    }

    
    public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length();
        ensureCapacityInternal(count + len);
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }
    
    //...
}

image.png

这也是建造者模式的体现。

Mybatis的 SqlSessionFactoryBuilder 就使用了 builder模式

image.png

这一堆的 build 方法返回都是 SqlSessionFactory ,调用不同的方法,可以构建出不同特性的 SqlSessionFactory

小结

  • 相同的方法,不同的执行顺序,产生不同的事件结果时,可以采用建造者模式。
  • 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能,这个时候使用建造者模式非常合适。
  • 多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时,则可以使用该模式。

无需记忆,自然使用。

点个赞再走吧~