Spring项目开发-建造者模式

提示: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注解构建对象过程。还是那句话,知其然知其所以然才是能力提升的根本,共勉。

<think>好的,用户想了解建造者模式的应用场景和示例。我需要先回忆建造者模式的基本概念。建造者模式属于创建型设计模式,主要用于分离复杂对象的构建和表示,使得同样的构建过程可以创建不同的表示。 首先,应用场景方面,根据之前的引用资料,建造者模式适用于需要灵活组装对象的构建过程的情况。比如,当对象的构造步骤很多,或者需要不同的组合时。常见的例子包括自定义电脑配置、复杂文档生成、餐饮套餐组合等。 接下来要考虑用户可能的背景。用户可能是软件开发人员,或者在学习设计模式,需要实际应用示例来理解理论。所以,回答时要结合具体场景,给出代码示例,这样更直观。 需要确保回答的结构清晰,按照定义、应用场景、代码示例、优点的顺序展开。应用场景部分要分点说明,每个场景都举实际的例子,比如引用中提到的电脑组装、文档生成器。同时,引用资料中的例子要正确标注来源,比如引用[4]提到的动态组装自定义电脑。 代码示例部分,用户可能更熟悉Java,因为引用中的示例都是Java相关的。需要提供一个简单的Java示例,展示建造者模式的结构,包括产品、建造者、指导者等角色。代码要符合语法规范,并且注释清楚每个部分的作用。 另外,用户可能想知道建造者模式的优点,比如解耦构建过程和表示,方便扩展等。这些也需要在回答中提到,帮助用户全面理解为什么使用该模式。 最后,生成相关问题时要围绕建造者模式的延伸,比如与工厂模式的区别,实际框架中的应用,如何支持扩展等。这样用户如果有进一步的问题,可以继续深入学习。 检查是否遗漏了引用中的信息。引用[3]提到建造者模式涉及产品、抽象建造者、具体建造者、指导者和客户端,这些在代码示例中都要体现出来。同时,确保引用的标识正确,比如每个场景后的引用标注。 总结回答的结构:先定义建造者模式,然后分点列出应用场景,每个场景附示例和引用,接着给出代码示例,说明优点,最后相关问题。这样用户能逐步理解,结构清晰。</think>### 建造者模式的应用场景与示例 #### 1. 建造者模式的定义 建造者模式是一种**创建型设计模式**,用于**分离复杂对象的构建过程与其表示**,使得同样的构建过程可以创建不同的表示。通过将对象的构建步骤拆解为独立的方法,并由指导者(Director)协调构建流程,实现灵活的对象组装[^3][^4]。 --- #### 2. 核心应用场景 1. **需要灵活组装复杂对象** 当对象的构造过程包含多个步骤,且不同场景需要不同的组合时,例如: - **自定义电脑配置**:根据用户需求动态选择CPU、内存、硬盘等组件[^4]。 - **餐饮套餐组合**:定义基础套餐,允许用户添加或替换菜品。 2. **避免构造方法参数过多** 若对象的构造函数需要大量参数(尤其是可选参数),建造者模式可通过链式调用逐步设置参数,提升代码可读性。例如: ```java Computer computer = new Computer.Builder("Intel i7") .setMemory("16GB") .setStorage("1TB SSD") .build(); ``` 3. **需要构建不可变对象** 通过建造者逐步设置属性,最终调用`build()`生成不可变对象,确保线程安全。例如Java中的`StringBuilder`最终生成`String`[^2]。 4. **支持多维度对象变体** 当同一类对象需要不同表现形式(如HTML/PDF格式的文档),可通过不同建造者实现差异化构建逻辑。 --- #### 3. 代码示例(Java实现) ```java // 产品类:最终生成的电脑 class Computer { private String cpu; private String memory; private String storage; private Computer(Builder builder) { this.cpu = builder.cpu; this.memory = builder.memory; this.storage = builder.storage; } // 建造者类 public static class Builder { private String cpu; // 必选参数 private String memory = "8GB"; // 可选参数默认值 private String storage = "512GB HDD"; public Builder(String cpu) { this.cpu = cpu; } public Builder setMemory(String memory) { this.memory = memory; return this; } public Builder setStorage(String storage) { this.storage = storage; return this; } public Computer build() { return new Computer(this); } } } // 客户端调用 public class Client { public static void main(String[] args) { Computer highEndPC = new Computer.Builder("AMD Ryzen 9") .setMemory("32GB") .setStorage("2TB NVMe SSD") .build(); } } ``` **代码说明**: - `Computer`类通过内部静态类`Builder`逐步设置属性,最终通过`build()`生成对象。 - 必选参数通过`Builder`构造函数传入,可选参数通过链式方法设置,避免构造函数臃肿[^3]。 --- #### 4. 实际框架中的应用 - **Java标准库**:`StringBuilder`和`StringBuffer`通过`append()`方法构建字符串,最终调用`toString()`生成结果[^2]。 - **Spring框架**:`BeanDefinitionBuilder`用于动态构建Bean定义,支持链式配置作用域、属性等。 --- #### 5. 优点总结 1. **解耦构建与表示**:客户端无需关注对象内部组成细节。 2. **灵活扩展**:新增建造者即可支持新的对象变体。 3. **代码可维护性**:避免重叠构造器(Telescoping Constructor)问题。 --- §§ 1. 建造者模式与工厂模式的核心区别是什么? 2. 如何在Spring框架中结合建造者模式管理Bean? 3. 建造者模式如何支持对象的“部分参数可选”特性? 4. 如果一个对象的构建过程需要动态调整顺序,建造者模式如何实现?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值