Java Builder模式实现原理及优缺点解析

Builder 模式中文叫作建造者模式,又叫生成器模式,它属于对象创建型模式,是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节。下图是建造者模式的通用类图:

在建造者模式中,有如下4种角色:

  • Product:产品角色
  • Builder:抽象建造者,定义产品接口
  • ConcreteBuilder:具体建造者,实现Builder定义的接口,并且返回组装好的产品
  • Director:指挥者,属于这里面的老大,你需要生产什么产品都直接找它。

建造者模式应用举例

家装

家装不管是精装还是简装,它的流程都相对固定,所以它适用于建造者模式。我们就以家装为例,一起来学习了解一下建造者模式。下图是家装建造者模式简单的 UML 图。

1、家装对象类

/**
 * 家装对象类
 */
public class House {
  // 买家电
  private String jiadian;

  // 买地板
  private String diban;
  // 买油漆
  private String youqi;

  public String getJiadian() {
    return jiadian;
  }

  public void setJiadian(String jiadian) {
    this.jiadian = jiadian;
  }

  public String getDiban() {
    return diban;
  }

  public void setDiban(String diban) {
    this.diban = diban;
  }

  public String getYouqi() {
    return youqi;
  }

  public void setYouqi(String youqi) {
    this.youqi = youqi;
  }

  @Override
  public String toString() {
    return "House{" +
        "jiadian='" + jiadian + '\'' +
        ", diban='" + diban + '\'' +
        ", youqi='" + youqi + '\'' +
        '}';
  }
}

2、抽象建造者 Builder 类

/**
 * 抽象建造者
 */
public interface HouseBuilder {
  // 买家电
  void doJiadian();
  // 买地板
  void doDiBan();
  // 买油漆
  void doYouqi();

  House getHouse();
}

3、具体建造者-简装建造者类

/**
 * 简装创建者
 */
public class JianzhuangBuilder implements HouseBuilder {

  private House house = new House();

  @Override
  public void doJiadian() {
    house.setJiadian("简单家电就好");
  }

  @Override
  public void doDiBan() {
    house.setDiban("普通地板");
  }

  @Override
  public void doYouqi() {
    house.setYouqi("污染较小的油漆就行");
  }

  @Override
  public House getHouse() {
    return house;
  }
}

4、具体建造者-精装建造者类

/**
 * 精装创建者
 */
public class jingzhuangBuilder implements HouseBuilder {

  private House house = new House();

  @Override
  public void doJiadian() {
    house.setJiadian("二话不说,最好的");
  }

  @Override
  public void doDiBan() {
    house.setDiban("二话不说,实木地板");
  }

  @Override
  public void doYouqi() {
    house.setYouqi("二话不说,给我来0污染的");
  }

  @Override
  public House getHouse() {
    return house;
  }
}

5、指挥官-家装公司类

/**
 * 家装公司,值需要告诉他精装还是简装
 */
public class HouseDirector {

  public House builder(HouseBuilder houseBuilder){
    houseBuilder.doDiBan();
    houseBuilder.doJiadian();
    houseBuilder.doYouqi();
    return houseBuilder.getHouse();
  }
}

6、测试

public class App {
  public static void main(String[] args) {
    house();
  }

  public static void house(){
    HouseDirector houseDirector = new HouseDirector();
    // 简装
    JianzhuangBuilder jianzhuangBuilder = new JianzhuangBuilder();
    System.out.println("我要简装");
    System.out.println(houseDirector.builder(jianzhuangBuilder));

    // 精装
    jingzhuangBuilder jingzhuangBuilder = new jingzhuangBuilder();
    System.out.println("我要精装");
    System.out.println(houseDirector.builder(jingzhuangBuilder));

  }
}

输出结果

我们以家装为例,实现了两个具体的建造者,一个简装建造者、一个精装建造者。我们只需要告诉家装公司,我是需要简装还是精装,他会去帮我们安排,我不需要知道里面具体的细节。怎么样,建造者模式学回了吗?

对象构建

在日常开发中,你是不是会经常看到下面这种代码:

return new Docket(DocumentationType.SWAGGER_2)
    .apiInfo(apiInfo())
    .select()
    .apis(RequestHandlerSelectors.basePackage("com.curry.springbootswagger.controller"))
    .paths(PathSelectors.any())
    .build();

是不是很优美?学会了 Builder 模式之后,你也可以通过这种方式进行对象构建。它是通过变种的 Builder 模式实现的。先不解释了,我们先用 Builder 模式来实现跟上述的对象构建,使用学生类为例。

学生对象代码:

public class Student {

  private String name;

  private int age;

  private int num;

  private String email;

  // 提供一个静态builder方法
  public static Student.Builder builder() {
    return new Student.Builder();
  }
  // 外部调用builder类的属性接口进行设值。
  public static class Builder{
    private String name;

    private int age;

    private int num;

    private String email;

    public Builder name(String name) {
      this.name = name;
      return this;
    }

    public Builder age(int age) {
      this.age = age;
      return this;
    }

    public Builder num(int num) {
      this.num = num;
      return this;
    }

    public Builder email(String email) {
      this.email = email;
      return this;
    }

    public Student build() {
      // 将builder对象传入到学生构造函数
      return new Student(this);
    }
  }
  // 私有化构造器
  private Student(Builder builder) {
    name = builder.name;
    age = builder.age;
    num = builder.num;
    email = builder.email;
  }

  @Override
  public String toString() {
    return "Student{" +
        "name='" + name + '\'' +
        ", age=" + age +
        ", num=" + num +
        ", email='" + email + '\'' +
        '}';
  }
}

调用代码:

  public static void student(){
    Student student = Student.builder().name("平头哥").num(1).age(18).email("平头哥@163.com").build();
    System.out.println(student);
  }

可以看到,变种 Builder 模式包括以下内容:

  • 在要构建的类内部创建一个静态内部类 Builder
  • 静态内部类的参数与构建类一致
  • 构建类的构造参数是 静态内部类,使用静态内部类的变量一一赋值给构建类
  • 静态内部类提供参数的 setter 方法,并且返回值是当前 Builder 对象
  • 最终提供一个 build 方法构建一个构建类的对象,参数是当前 Builder 对象

可能你会说,这种写法实现太麻烦了,确实需要我们写很多额外的代码,好在前辈们已经开发出了lombok来拯救我们,我们只需要引入lombok插件,然后在实体类上添加@Builder注解,你就可以实用 Builder 模式构建对象了。

建造者模式的优缺点

优点

  • 在建造者模式中, 客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象
  • 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者, 用户使用不同的具体建造者即可得到不同的产品对象
  • 可以更加精细地控制产品的创建过程 。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程
  • 增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合“开闭原则”

缺点

  • 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
  • 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Java设计模式之建造者模式(Builder模式)介绍

    Builder模式定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. Builder模式是一步一步创建一个复杂的对象,它允许用户可以只通过指定复杂对象的类型和内容就可以构建它们.用户不知道内部的具体构建细节.Builder模式是非常类似抽象工厂模式,细微的区别大概只有在反复使用中才能体会到. 为何使用建造者模式 是为了将构建复杂对象的过程和它的部件解耦.注意:是解耦过程和部件. 因为一个复杂的对象,不但有很多大量组成部分,如汽车,有很多部件:车轮.方向盘.发动机,还

  • Java设计模式之Builder建造者模式

    一.场景描述 建造者模式同工厂模式.抽象工厂模式一样,用于创建继承类对象. 工厂模式:Java设计模式之工厂模式 抽象工厂模式:Java设计模式之抽象工厂模式 所不同的是,工厂模式下,各子类实现接口,通过工厂类创建子类对象:而建造者模式下,各子类拥有其建造者类,通过它创建不同的父类对象,最终实现多态,实际上子类.父类在代码中是不存在的. 以仪器数据采集工具为例,工厂模式下,定义接口"仪器数据采集工具",定义子类"PDF文件数据采集工具"和"Excel文件数

  • Java中Builder模式的实现详解

    前言 本文主要给大家介绍了关于如何实现Builder模式,大家在构建大对象时,对象的属性比较多,我们可以采用一个构造器或者使用空的构造器构造,然后使用setter方法去设置.在使用者使用这些方法时,会很多冗长的构造器参数列表或者setter方法.我们可以使用Builder模式来简化大对象的构造,提高代码的简洁性,同时提高使用者的编码体验. 下面我们将介绍在Java8之前.使用极简代码利器Lombok.Java8之后的Builder模式. Pre Java8 我们先来看下在Java8之前的Buil

  • 详解java构建者模式Builder

    定义 Builder模式是一步步创建一个复杂对象的创建型模式,它允许用户在不知道内部构建细节的情况下,可以更精细的控制对象的构建过程.该模式是将构建复杂对象的过程和它的部件解耦,使得构建过程和部件的表示隔离. 作为复杂对象可能有很多组成部分,比如汽车有车轮.方向盘.发动机.变速箱还有各种小零件等,如何将这些部件组装成一台汽车,这个装配的过程漫长且复杂,对于这种情况,为了对外部隐藏实现细节,就可以使用Builder模式将部件和组装过程分离,使得构建过程和部件分离可自由扩展,两者之间的耦合也降到最低

  • Java Builder Pattern建造者模式详解及实例

    Java Builder Pattern 1.概念 将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示. [构建与表示分离,同构建不同表示] 与抽象工厂的区别:在建造者模式里,有个指导者,由指导者来管理建造者,用户是与指导者联系的,指导者联系建造者最后得到产品.即建造模式可以强制实行一种分步骤进行的建造过程. 建造模式是将复杂的内部创建封装在内部,对于外部调用的人来说,只需要传入建造者和建造工具,对于内部是如何建造成成品的,调用者无需关心. 举个简单的例子,如汽车,有很多部件,

  • Java Builder模式构建MAP/LIST的实例讲解

    我们在构建一个MAP时,要不停的调用put,有时候看着觉得很麻烦,刚好,看了下builder模式,觉得这思路不错,于是乎,照着用builder模式写了一个构建MAP的示例, 代码如下: import java.util.HashMap; import java.util.Map; public class MapBuilder<T> { public Builder<T> b; public MapBuilder(Builder<T> b){ this.b = b; }

  • Java设计中的Builder模式的介绍

    概述 Builder模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 使用场景 相同的方法,不同的执行顺序,产生不同的事件结果 多个部件或零件,都可以装配到一个对象中,但产生的运行结果又不相同时 产品类非常复杂,或者产品类中的调用顺序不同产生不同的作用 当初始化一个对象特别复杂,如参数多,且很多参数都具有默认值时 下面从一个Person例子进行分析重叠构造器模式.JavaBeans模式.Builder模式的使用.Person类有两个必要参数(id和name),有5

  • java实现建造者模式(Builder Pattern)

    一.什么是建筑者模式?   建造者模式(Builder Pattern)使用多个简单的对象一步一步构建一个复杂的对象.   一个 Builder 类会一步一步构造最终的对象,该 Builder 类独立于其他对象.   建造者模式主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成:由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定. 二.建造者模式的具体实现 结构图 建造者模式中的四个角色:

  • Java Builder模式实现原理及优缺点解析

    Builder 模式中文叫作建造者模式,又叫生成器模式,它属于对象创建型模式,是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示.建造者模式是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节.下图是建造者模式的通用类图: 在建造者模式中,有如下4种角色: Product:产品角色 Builder:抽象建造者,定义产品接口 ConcreteBuilder:具体建造者,实现Builder定义的接口,并且返回组

  • Java方法重载Overload原理及使用解析

    这篇文章主要介绍了Java方法重载Overload原理及使用解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 为什么要用方法重载: 对于功能类似的方法来说,因为参数列表不一样,如果定义不同名称的方法,太麻烦且难以记忆. 为了解决这个问题,引入方法的重载. 重载的定义: 多个方法的名称一样,但参数列表不一样. 不使用方法重载 定义三个功能类似的方法 public class TestOverload { public static int su

  • Java图形界面Swing原理及用法解析

    这篇文章主要介绍了Java图形界面Swing原理及用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 JButton组件 布局管理器 FlowLayout 流式布局 BorderLayout 方位布局 GridLayout 表格布局 绝对布局 JLable 组件 文本框组件 JPanel轻量级容器 创建事件监听类 (更换监听类实现监听) 窗口监听适配器 都可使用匿名类实现监听 每个监听方法都可以返回一个Event对象来返回监听值 以上就是本

  • java阻塞队列实现原理及实例解析

    这篇文章主要介绍了java阻塞队列实现原理及实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 阻塞队列与普通队列的不同在于.当队列是空的时候,从队列中获取元素的操作将会被阻塞,或者当队列满时,往队列里面添加元素将会被阻塞.试图从空的阻塞队列中获取元素的线程将会被阻塞,直到其他的线程往空的队列插入新的元素.同样,试图往已满的阻塞队列中添加新元素的线程同样也会被阻塞,直到其他的线程使队列重新变得空闲起来,如从队列中移除一个或者多个元素,或者完

  • Java内存模型原子性原理及实例解析

    这篇文章主要介绍了Java内存模型原子性原理及实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 本文就具体来讲讲JMM是如何保证共享变量访问的原子性的. 原子性问题 原子性是指:一个或多个操作,要么全部执行且在执行过程中不被任何因素打断,要么全部不执行. 下面就是一段会出现原子性问题的代码: public class AtomicProblem { private static Logger logger = LoggerFactory.

  • Java原子变量类原理及实例解析

    这篇文章主要介绍了Java原子变量类原理及实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.原子变量类简介 为何需要原子变量类 保证线程安全是 Java 并发编程必须要解决的重要问题.Java 从原子性.可见性.有序性这三大特性入手,确保多线程的数据一致性. 确保线程安全最常见的做法是利用锁机制(Lock.sychronized)来对共享数据做互斥同步,这样在同一个时刻,只有一个线程可以执行某个方法或者某个代码块,那么操作必然是原子性

  • java 工厂模式的讲解及优缺点的介绍

    简单工厂模式介绍: 概要: 简单工厂模式,又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式.在简单工厂模式中,把产品的生产方法封装起来放进工厂类,工厂类可以根据参数的不同返回不同产品类的实例.工厂类就是用来生产产品的类,把生产产品的方法放到工厂类里面去,工厂类里面用switch语句控制生产哪种商品,使用者只需要调用工厂类的静态方法就可以实现产品类的实例化. 实现代码: package scut.designmodel.SimpleFactoryPatter

  • Java Lock接口实现原理及实例解析

    1.概述 JUC中locks包下常用的类与接口图如下: 图中,Lock和ReadWriteLock是顶层锁的接口,Lock代表实现类是ReentrantLock(可重入锁),ReadWriteLock(读写锁)的代表实现类是ReentrantReadWriteLock. ReadWriteLock 接口以类似方式定义了读锁而写锁.此包只提供了一个实现,即 ReentrantReadWriteLock. Condition 接口描述了可能会与锁有关联的条件变量.这些变量在用法上与使用 Object

  • Java基数排序radix sort原理及用法解析

    基数排序(桶排序)介绍 基数排序(radix sort)属于"分配式排序"(distribution sort),又称"桶子法"(bucket sort)或bin sort,顾名思义,它是通过键值的各个位的值,将要排序的元素分配至某些"桶"中,达到排序的作用 基数排序法是属于稳定性的排序,基数排序法的是效率高的稳定性排序法 基数排序(Radix Sort)是桶排序的扩展 基数排序是1887年赫尔曼·何乐礼发明的.它是这样实现的:将整数按位数切割成

随机推荐