提示:Spring框架中好像是未用到建造者模式,之所有将建造者模式写入本专栏,是为了方便将开发中所遇到的设计模式统一归纳总结
文章目录
前言
提示:介绍设计模式在项目开发的使用:
基本概念:设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
黑马程序员教程对设计模式的叙述:一个问题通常有 N 种解法,其中肯定有一种解法是最优的,这个最优的解法被总结出来,称之为设计模式
本篇文章记录在开发过程所用到的 23种 设计模式之一的建造者模式
提示:以下是本篇文章正文内容,下面案例仅供参考
一、建造者模式概念
建造者模式(Builder Pattern)是一种创建型设计模式,主要用于创建复杂对象。它的核心思想是将对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。
优点:
分步构建对象:允许按照步骤和顺序构建复杂对象,使得构建过程更加灵活,可以控制每个部分的构建细节。
复用性:可以复用相同的建造过程来构建不同的表示,只需要不同的具体建造者即可。
封装性:隐藏了复杂对象的创建和装配过程,使得客户端无需关心具体的构建细节。
二、Java建造者模式
(一)创建任意实体类
代码如下(示例):
public class Student {
private Long sId;
private String sName;
private String sSex;
private String sClass;
public Long getsId() {
return sId;
}
public void setsId(Long sId) {
this.sId = sId;
}
public String getsName() {
return sName;
}
public void setsName(String sName) {
this.sName = sName;
}
public String getsSex() {
return sSex;
}
public void setsSex(String sSex) {
this.sSex = sSex;
}
public String getsClass() {
return sClass;
}
public void setsClass(String sClass) {
this.sClass = sClass;
}
// 1、无参构造方法
public Student() {
}
// 2、有参构造方法
public Student(Long sId, String sName, String sSex, String sClass) {
this.sId = sId;
this.sName = sName;
this.sSex = sSex;
this.sClass = sClass;
}
@Override
public String toString() {
return "Student{" +
"sId=" + sId +
", sName='" + sName + '\'' +
", sSex='" + sSex + '\'' +
", sClass='" + sClass + '\'' +
'}';
}
}
(二)创建实体类对象
(1)无参构造方法创建对象
@Test
public void test(){
Student studentOne = new Student();
studentOne.setsId(1L);
studentOne.setsName("张三");
System.out.println(studentOne);
}
输出结果:
Student{sId=1, sName='张三', sSex='null', sClass='null'}
(2)有参构造方法创建对象
@Test
public void test(){
Student studentTwo = new Student(2L,"李四","男","计科17甲");
System.out.println(studentTwo);
}
输出结果:
Student{sId=2, sName='李四', sSex='男', sClass='计科17甲'}
(3)建造者模式创建对象
从上述无参构造和有参构造方法中我们可以看出,如果我想得到一个 Student 的对象,并且为这个对象的属性设置值。
第一种方法:可以通过无参构造方法,获取一个对象,给这个对象的属性一一赋值(可以不是全部赋值)。
第二种方法:通过有参构造方法,在创建对象时候为对象的属性赋值。
现在有个问题,以上的 Student 这个类,只有四个属性(sId,sName,sSex,sClass),假设这个类中有一百个属性,然后在不同场景下我所需要的 Student 的对象 的属性赋值是不一样,比如 studentOne,我只要sId这个属性赋值,其它属性为空,studentOne,我只要sId,sName这两个属性赋值,其它属性为空。依次类推,那我们只能通过无参构造,得到一个对象后,依次通过set()方法为属性赋值(当然我知道有BeanUtils.copyProperties()工具可以拷贝赋值属性值)或者是在 Student 类中,创建 101个 构造无法,分别从无参到 1 个参数 2 个参数…100个参数构造方法,如果属性字段类型不同,还得考虑排列组合,不只是101个构造方法。
所以建造者模式就是为了解决这个问题,将 Student 类改造一下
public class Student {
private Long sId;
private String sName;
private String sSex;
private String sClass;
public Long getSId() {
return sId;
}
public String getSName() {
return sName;
}
public String getSSex() {
return sSex;
}
public String getSClass() {
return sClass;
}
private Student(Builder builder){
this.sId = builder.sId;
this.sName = builder.sName;
this.sSex = builder.sSex;
this.sClass = builder.sClass;
}
public static class Builder{
private Long sId;
private String sName;
private String sSex;
private String sClass;
public Builder sId(Long sId){
this.sId = sId;
return this;
}
public Builder sName(String sName){
this.sName = sName;
return this;
}
public Builder sSex(String sSex){
this.sSex = sSex;
return this;
}
public Builder sClass(String sClass){
this.sClass = sClass;
return this;
}
public Student build(){
return new Student(this);
}
}
@Override
public String toString() {
return "Student{" +
"sId=" + sId +
", sName='" + sName + '\'' +
", sSex='" + sSex + '\'' +
", sClass='" + sClass + '\'' +
'}';
}
}
将类中的属性的set()方法通过静态类Builder来赋值,私有化类的构造函数,并且参数是Builder类对象。下面我们来测试创建不同对象
@Test
public void test(){
Student studentOne = new Student.Builder().build();
System.out.println(studentOne);
Student studentTwo = new Student.Builder().sId(2L).build();
System.out.println(studentTwo);
Student studentThree = new Student.Builder().sId(3L).sName("张三").build();
System.out.println(studentThree);
Student studentFour = new Student.Builder().sId(4L).sClass("计科17甲").build();
System.out.println(studentFour);
}
输出结果:
Student{sId=null, sName='null', sSex='null', sClass='null'}
Student{sId=2, sName='null', sSex='null', sClass='null'}
Student{sId=3, sName='张三', sSex='null', sClass='null'}
Student{sId=4, sName='null', sSex='null', sClass='计科17甲'}
从输出结果可以看出,我们可以通过建造者模式,创建出我们想要的对象,比如学生1 属性都为空;学生2 只有学号,其余都为空;学生3 只有学号和姓名,其余都为空,等等。。。。
三、lombok建造者模式
lombok工具相信很多人在实际开发过程中都会用到,他为我们提供了很多注解来减少JavaBean中的get()方法,set()方法,toString()方法等等。其中lombok中的一个 @Builder 这个注解就是为我们的JavaBean提供了构建对象方法。@Builder 注解原理就是采用建造者模式。
下面我们使用@Builder注解来创建对象
(一)项目中添加依赖
lombok依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
</dependency>
(二)创建实体类
创建实体类,并在实体类上添加 @Builder注解 @ToString 注解
@ToString
@Builder
public class Person {
private Long id ;
private String name;
private Integer age ;
private String address ;
}
(三)测试类看效果
@Test
public void test(){
Person personOne = Person.builder().build();
System.out.println(personOne);
Person personTwo = Person.builder().id(2L).build();
System.out.println(personTwo);
Person personThree = Person.builder().id(3L).name("张三").build();
System.out.println(personThree);
Person personFour = Person.builder().id(4L).name("李四").age(18).address("北京").build();
System.out.println(personFour);
}
输出结果:
Person(id=null, name=null, age=null, address=null)
Person(id=2, name=null, age=null, address=null)
Person(id=3, name=张三, age=null, address=null)
Person(id=4, name=李四, age=18, address=北京)
从上述使用 @Builder注解可以看出,跟我们使用建造者模式创建对象基本一样的。
(四)使用@Builder注解问题
当我们使用@Builder注解时,会检查我们类中属性必须有默认值的,不然会提示错误信息,例如:我们将 age 属性类型从 Integer 变成 int 类型
@ToString
@Builder
public class Person {
private Long id ;
private String name;
private int age ; // 这里类型从 包装类变成 基本数据类型
private String address ;
}
如下错误信息
翻译就是:Lombok生成器缺少不可为null的字段。
可是这就很奇怪,之前我们 personOne 对象中的属性就是全部为空,为什么将 包装类Integer 变成 基本数据类型 int 就不行了呢?但是我们运行一下后,虽然报错,但是还是能正常输出结果。
解决方案就是,我们字段全部都用包装类,或者在字段上加上注解,添加默认值既可以。错误信息就会消失
@ToString
@Builder
public class Person {
private Long id ;
private String name;
@Builder.Default
private int age = 0 ; //注意这里的变化
private String address ;
}
当然了,我们也可以在上述的 Student类中 加入
private int age;
这个属性,并且我们不为它设置初始值是没有问题的,输出结果是0,java中的基本概念:基本数据类型的默认值适用于实例变量(类的成员变量)和类变量(静态变量),它们在声明时会根据数据类型自动获得默认值,但局部变量不会。
总结
以上就是我们在开发中常见并且会使用设计模式 - 建造者模式,并且我们将 java代码 形式来叙述@Builder注解构建对象过程。还是那句话,知其然知其所以然才是能力提升的根本,共勉。