Effective Java 1.多参数构造时使用构建器

本文介绍如何在Java和Scala中使用构建器模式解决大量可选参数的问题。通过实例演示了构建器模式的基本原理及其在实际开发中的应用,如SparkConf的配置过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.引言

静态工厂和构造器有个共同的局限性:它们都不能很好地扩展到大量的可选参数。当初始化类需要较少的参数是,Java 可以尝试实现多种构造方法,scala 相同,可以重载多种apply方法,但是当参数过多时,维护多个构造器将变得困难且难以理解。例如一个User用户类包含10-20个属性,如果我们初始化一个用户类 new User("abc",‘a","b","c",...,"z"),很容易混淆参数,这时候构建器 Builder 就派上用场。

 

2.构建器Demo

其实在日常程序编写时,经常用到构建器,SparkConf 就是其中之一。初始化spark的过程是先初始化SparkConf类,然后进行各项参数的配置,然后初始化SparkContext类,将SparkConf传入sparkContext 生成 spark。这里 SparkConf 类的作用就是 Builder,SparkContext就是具体要构建的类。

    val conf = new SparkConf().setAppName("test").setMaster("local[2]").set("spark.hadoop.validateOutputSpecs", "false")
    val sc = new SparkContext(conf)

 

3.Java实现

User类

用户类只写了两个属性,实际情况可能有数十种属性。在用户类内定义静态方法 Builder 负责创建构建器,所有的默认参数都放在 Builder 类内,最后 Builder 类里要内嵌一个 build 方法,负责生成我们要的用户类。注意到 Builder 类内设置方法的参数都会返回 this 即自己本身,所以可以链式的调用自己,从而可以像 Spark 那样一直在后面追加参数。

public class User {
    private String name;
    private Integer age;

    private User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return this.name;
    }

    // 创建builder的静态方法
    public static Builder builder() {
        return new Builder();
    }

    // 通过builder构造用户
    public static class Builder {
        private String name;
        private Integer age;

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

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

        public User build() {
            return new User(name, age);
        }
    }

}

Main类

public class Main {
    public static void main(String[] args) {
        User.Builder builder = User.builder().setName("test").setAge(25);
        User user = builder.build();
        System.out.println("name: " + user.getName());
    }
}

通过 getName 方法得到 Builder 内设置的参数。

 

4.Scala实现

scala实现与java大同小异,这里userBuilder类的身份就像是 sparkConf,User类就像是 SparkContext,最终获取用户类。

class User(builder: userBuilder) {
  val name = builder.name
  val mode = builder.mode
}

class userBuilder {
  var name: String = _
  var mode: String = _

  def setName(name: String): userBuilder = {
    this.name = name
    this
  }

  def setMode(mode: String): userBuilder = {
    this.mode = mode
    this
  }

  def build(): User = {
    new User(this)
  }
}

object Robot {
  def main(args: Array[String]): Unit = {
    // 类似于用sparkConf构造spark
    val User = new userBuilder()
      .setName("abc")
      .setMode("test")
      .build()

    println(User.name)
  }
}

 

5.回看

这里再回看上面 Spark 的方法和上述实现的方法,有相同之处也有不同之处,相同之处是都使用了链式构造参数方法。SpackConf 代码内多个set方法都基于下述set方法开发,可以看到最后返回this,和上面样例相似。不同之处是初始化 SparkConf 并没有用到 build 方法,这是因为 SparkContext 内置了 this 方法,会根据 SparkConf 构造本身,这里只列出最基础的 SparkContext 构造方法,源码内还有多种 this 构造方法,类似于实现多种 apply 方法,有兴趣可以看看。 

SparkConf

  private[spark] def set(key: String, value: String, silent: Boolean): SparkConf = {
    if (key == null) {
      throw new NullPointerException("null key")
    }
    if (value == null) {
      throw new NullPointerException("null value for " + key)
    }
    if (!silent) {
      logDeprecationWarning(key)
    }
    settings.put(key, value)
    this
  }

SparkContext 

def this() = this(new SparkConf())

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BIT_666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值