构建器

作者: 睦月MTK | 来源:发表于2020-01-25 22:17 被阅读0次

statement:本篇内容只是建立在我目前经验的基础之上,必然有不完善甚至是不正确的地方,请谨慎阅读,如果能指出错误与不足之处,更是不甚感激


一、问题引入与分析
  • 问题引入:假设目前有一个BuilderTest类,该类中有多达20个域,分别名为field1field2...field20,其中field1field2是必选域,其他18个是可选域,那么该如何去设计这个类呢?
  • 问题分析:你可能会自然的想到使用一个包含field1field2两个类型的参数的构造器,加上其他18个域的setter方法的方案来设计这个类。但是你有没有想过这么几个问题?
    1. 实例的创建先于可选域的添加之前,简而言之就是我必须得先实例化对象出来然后再调用setter方法给该实例添加可选域吧,而先实例化对象这种操作总是会隐含不必要的风险,所以这也是构造器的优点所在,构造器确保所有操作完成后再将一个完整的实例交付给使用者。但对于本问题,全部使用构造器来设置可选域更不现实。
    2. 使用setter方法就说明你并不打算把这个类设置成不可变类,那么这个类必然在并发问题上需要多思考一番(不明白?因为不可变类必定是线程安全的啦!!!当然你也可以选择在所有可选域设置完成之后,自我保证再也不动这个实例的状态,这样这个实例也是线程安全的,这叫事实不可变类,但显然你不能保证,人是容易犯错的)

二、解决问题的另一种方案--构建器
  • 构建器的示例
interface ClassBuilder<T>{
    T build();
}

public class BuilderTest {
    //必选域
    private final int field1;
    private final int field2;
    //可选域
    private final int field3;
    //省略...
    private final int field20;
    
    public static class Builder implements ClassBuilder<BuilderTest>{
        //必选域
        private final int field1;
        private final int field2;
        //可选域
        private int field3;
        //省略...
        private int field20;
        
        public Builder(int field1 , int field2) {
            //必要的参数合法性检测代码...
            this.field1 = field1;
            this.field2 = field2;
        }
        
        public Builder setField3(int field3) {
            //必要的参数合法性检测代码...
            this.field3 = field3;
            return this;
        }
        public Builder setField20(int field20) {
            //必要的参数合法性检测代码...
            this.field20 = field20;
            return this;
        }
        
        @Override
        public BuilderTest build() {
            //必要的完整性检测代码...
            return new BuilderTest(this);
        }   
    }
    
    private BuilderTest(Builder builder) {
        this.field1 = builder.field1;
        this.field2 = builder.field2;
        this.field3 = builder.field3;
        this.field20 = builder.field20;
    }
    
    public static void main(String[] args) {
        BuilderTest test = new BuilderTest.Builder(20, 20).setField3(13).setField20(14).build();
    }
}

构建器其实就是使用一个静态内部类专门负责类字段的填充这一工作,一般取名为Builder,每个Builder都会有build方法,故将其抽离出来变成了一个接口


三、分析与总结
  • 由于BuilderTest类使用的是Builder对象作为参数,并从Builder对象中获取所需要的域的值,这样的写法简便且安全
  • 可能唯一的缺点就是对小型的类(字段并不多)非常不友好,所以并不建议在字段少的类中使用构建器

参考文档:
[1] 《Effective Java》

相关文章

  • 索引构建

    1 索引构建 索引构建 建立倒排索引的过程,就是索引构建 索引器 构建索引的程序或者计算机,就是索引器 索引器需要...

  • 遇到多个构造器参数时要考虑用构建器

    第二条:遇到多个构造器参数时要考虑用构建器。 1. 什么是构建器? 顾名思义,构建器就是用来构建一个类用的,具体做...

  • Postman中文文档——请求(Request)

    请求构建器 在构建器(Builder)选项卡下,请求构建器允许您快速创建任何类型的HTTP请求。HTTP请求包含四...

  • kotlin<第八篇>:协程的启动与取消

    一、启动构建器 launch与async构建器都用来启动新协程: 等待一个作业: 二、启动模式 三、作用域构建器 ...

  • 构建器

    statement:本篇内容只是建立在我目前经验的基础之上,必然有不完善甚至是不正确的地方,请谨慎阅读,如果能指出...

  • 队列同步器AbstractQueuedSynchronizer

    概述队列同步器AbstractQueuedSynchronizer以下简称同步器,是用来构建锁或者构建其他同步组件...

  • Effective Java中构建器Builder的理解

    在Effective Java中, 有对构建器的讲解, 看了 java中Builder构建器的理解 之后, 了解...

  • GLSL_粒子动画

    1.顶点着色器的构建 1.构建顶点着色器时需要传入的参数 2.顶点着色器main()函数 2.片元着色器的构建 1...

  • Jenkins——实际项目设置

    【环境】maven、git1、新建项目【General】 【源码管理】 【构建触发器】 【构建环境】 【构建】 【...

  • vue独立构建和运行构建

    有两种构建方式,独立构建和运行构建。它们的区别在于前者包含模板编译器而后者不包含。 模板编译器:模板编译器的职责是...

网友评论

      本文标题:构建器

      本文链接:https://www.haomeiwen.com/subject/dwyrthtx.html