Builder模式

简介: 在Java编程中,常常需要为一个Bean构建成员变量或者构建参数,常用的方法有使用构造函数、使用JavaBean的set()方法,但是这两个方案或多或少都存在一定的缺点,于是今天的主角builder模式出场了,它解决了这种典型应用场景的问题,采用简洁明了的使用方式,灵活多变的链式调用,使得多个参数的Bean的构建变得十分简洁。

引言

在Java编程中,常常需要为一个Bean构建成员变量或者构建参数,常用的方法有使用构造函数、使用JavaBean的set()方法,但是这两个方案或多或少都存在一定的缺点,于是今天的主角builder模式出场了,它解决了这种典型应用场景的问题,采用简洁明了的使用方式,灵活多变的链式调用,使得多个参数的Bean的构建变得十分简洁。

本文从实际例子来看builder模式到底是什么?如何使用?

以下使用一个Student Bean来进行举例说明。

一、传统的构造函数

传统方式都是使用构造函数在构建Bean,例如存在一个学生类Student,包含id,name,age,height几个成员变量,其中idname是必须的,ageheight是可选的。如果使用传统的构造函数,一般情况下编码如下

public class Student {

   private final String name;

   private final int id;

   private final int age;

   private final int height;

   public Student(String name,int id,int age, int height){

       this.name = name;

       this.id = id;

       this.age = age;

       this.height = height;

   }

   public Student(String name,int id) {

       this(name,id,0,0);

   }

   public Student(String name,int id,int age){

       this(name,id,age,0);

   }

   

   public String getName() {

       return name;

   }

   public int getId() {

       return id;

   }

   public int getAge() {

       return age;

   }

   public int getHeight() {

       return height;

   }

   @Override

   public String toString() {

       return "Student{" +

               "name='" + name + '\'' +

               ", id=" + id +

               ", age=" + age +

               ", height=" + height +

               '}';

   }

   

}

存在的问题主要有两个

  1. 构造函数众多,显得十分繁琐,如果参数继续增加,则构造函数会更多
  2. 无法很好地区分参数,例如public Student(String name,int id,int age),可选地参数是age,但是从构造函数上很难看出来,并且由于height与age一样都是int类型,所以不能出现public Student(String name,int id,int age),也就是没办法实现只传入一个age或者一个height参数地情况,而是不得不使用public Student(String name,int id,int age, int height),即便我只是想设置一个height不想设置age,我也必须为这个age字段设置一个默认值。

二、JavaBean setter方法

为了解决以上问题,又一个经典地方案出现了,这就是JavaBean的setter方法,需要构造一个参数为空的构造函数,所有的成员变量通过setter方法进行设置。

publicclassStudent {

   private  Stringname;

   private  intid;

   private  intage;

   private  intheight;

   publicStudent(){

   }

   publicvoidsetName(Stringname) {

       this.name=name;

   }

   publicvoidsetId(intid) {

       this.id=id;

   }

   publicvoidsetAge(intage) {

       this.age=age;

   }

   publicvoidsetHeight(intheight) {

       this.height=height;

   }

   publicStringgetName() {

       returnname;

   }

   publicintgetId() {

       returnid;

   }

   publicintgetAge() {

       returnage;

   }

   publicintgetHeight() {

       returnheight;

   }

   @Override

   publicStringtoString() {

       return"Student{"+

               "name='"+name+'\''+

               ", id="+id+

               ", age="+age+

               ", height="+height+

               '}';

   }

}

这个方法也有比较明显的缺点,首先参数多的时候就需要调用很长的一系列setter方法,另外无法区分哪些是必须设置的成员变量,哪些是可选的成员变量,并且成员变量多的时候很容易漏掉一些setter,并且难以检查出来,很容易造成错误。

三、Builder模式

使用Builder模式使得这一切变得更加简洁,方便使用,先来看看Builder模式下如何编码

packagetech.liujintao.leetcode;

publicclassStudent {

   privatefinalStringname;

   privatefinalintid;

   privatefinalintage;

   privatefinalintheight;

   privateStudent(StudentBuilderstudentBuilder) {

       this.name=studentBuilder.name;

       this.id=studentBuilder.id;

       this.age=studentBuilder.age;

       this.height=studentBuilder.height;

   }

   publicstaticclassStudentBuilder

   {

       privateStringname;

       privateintid;

       privateintage;

       privateintheight;

       publicStudentBuilder(Stringname,intid)

       {

           this.name=name;

           this.id=id;

       }

       publicStudentBuilderage(intage)

       {

           this.age=age;

           returnthis;

       }

       publicStudentBuilderheight(intheight)

       {

           this.height=height;

           returnthis;

       }

       publicStudentbuild()

       {

           returnnewStudent(this);

       }

   }

   publicStringgetName() {

       returnname;

   }

   publicintgetId() {

       returnid;

   }

   publicintgetAge() {

       returnage;

   }

   publicintgetHeight() {

       returnheight;

   }

   @Override

   publicStringtoString() {

       return"Student{"+

               "name='"+name+'\''+

               ", id="+id+

               ", age="+age+

               ", height="+height+

               '}';

   }

   publicstaticvoidmain(String[] args) {

       Studentstudent=newStudentBuilder("codingway",111).age(18).height(2).build();

       System.out.println(student.toString());

   }

}

首先将Student类中的成员变量都声明为private final,并且将构造函数也声明为private,这样子就保证了无法通过Student的构造函数在构建Student Bean,并且成员变量也无法被修改,对外只提供getter方法用于或者成员变量。

随后构造一个StudentBuilder类,StudentBuilder类是一个静态类 ,其构造函数可以设置为Student必须的属性,例如id和name,其他可选的变量放到方法中,例如age和height,每个方法返回StudentBuilder本身。

Student对象只有一个构造函数,其参数就是StudentBuilder,于是所有成员变量地设置由StudentBuilder接管了,而StudentBuilder控制了哪些成员变量必须赋值,哪些是可选的,最后通过build方法构造Student Bean。使用者一目了然,链式调用更加清晰。

这就是Builder模式被大家所喜爱,并且在很多著名的开源项目中被采用的原因,特别是在一些需要配置环境参数并且参数众多的场景下。

相关文章
|
7月前
|
IDE Java 开发工具
@Builder这个注解的作用
@Builder这个注解的作用
229 0
|
5月前
@Builder 注解问题之如何在使用@Builder时设置默认值
@Builder 注解问题之如何在使用@Builder时设置默认值
391 0
|
5月前
@Builder 注解问题之@Builder生成的构造器存在问题如何解决
@Builder 注解问题之@Builder生成的构造器存在问题如何解决
134 0
|
7月前
builder 模式
builder 模式
41 0
|
设计模式 算法 Java
建造者模式(Builder Pattern)
建造者模式(Builder Pattern)是一种创建型设计模式,它可以将复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。
103 1
建造者模式(Builder Pattern) - alvinlkk的个人空间
建造者模式(Builder Pattern) - alvinlkk的个人空间
99 0
建造者模式(Builder Pattern) - alvinlkk的个人空间
Builder模式介绍
Builder模式是一步一步创建一个复杂对象的创建型模式,它允许用户在不知道内部构建细节的情况下,可以更精确地控制对象的构造流程。该模式是为了将构建复杂对象的过程和它的部件解耦,使得构建过程和部件的表示隔离开来。