引子

曾经在博文中发表过一些关于“Builder形式”的错误言辞,误导了读者。今日在此虔诚地向Builder形式道个歉。

这个错误言辞出现在面试题 | 怎么写一个又好又快的日志库?(一)。在该篇博文中,我如是说:

Kotlin 相较于 Java 的最大优势就是下降复杂度。在库接口设计及内部实现时就要充分发挥 Kotlin 的优势,比如 Kotlin 的国际里已不需要 Builder 形式了。

Builder 形式有如下优势:

  1. 为参数标示语义:在Builder形式中,每个特点的赋值都是一个函数,函数名标示了特点语义。
  2. 可选参数&分批赋值:Builder形式中,除了必选参数,其他参数是可选的,可分批赋值。而直接运用结构函数有必要一会儿为一切参数赋值。
  3. 添加参数约束条件:能够在参数不符合要求时,抛出反常。

但 Builder 形式也有价值,新增了一个中间类Builder

运用 Kotlin 的命名参数+参数默认值+require()语法,在没有任何副作用的情况下就能实现 Builder 形式:

class Person(
    val name: String,
    //'为以下可选参数设置默认值'
    val gender: Int = 1,
    val age: Int= 0,
    val height: Int = 0,
    val weight: Int = 0
)
//'运用命名参数构建 Person 实例'
val p  = Person(name = “taylor”,gender = 1,weight = 43)

命名参数为每个实参赋予了语义,而且不需要按结构方法中声明的次序来赋值,能够跳着来。

假如想添加参数约束条件能够调用require()方法:

data class Person(
    // 这个是必选参数
    val name: String,
    val gender: Int = 1,
    val age: Int= 0,
    val height: Int = 0,
    val weight: Int = 0
){
    //'在结构函数被调用的时分履行参数合法查看'
    init {
        require(name.isNotEmpty()){”name cant be empty“}
    }
}

此时假如像下面这样结构 Person,则会抛出反常:

val p = Person(name="",gender = 1)
java.lang.IllegalArgumentException: name cant be empty

本来在 build() 方法中履行的额定初始化逻辑也能够悉数写在init代码块中。

上述结论好像在给定的场景中找不出任何缺点。

但我遗漏了一个场景,“构建目标”和“特点赋值”是能够分开进行的。比如下面这个场景。

syntax = "proto3";
message Event {
 int64 time = 1; // 事情生成时刻
 string id = 2; // 事情唯一标识符
 string name = 3;// 事情称号
}
message BatchEvent {
  repeated Event event = 1;
}

运用 protobuf 界说了两个结构体,其中Event表明单个事情,而BatchEvent表明批量事情,它持有多个事情。

protobuf对应的java代码会运用建造者形式,这为构建批量事情提供了便利。

假设有一个事情流:

val initEvent = event {
    time = System.currentTimeMillis()
    id = UUID.randomUUID()
    name = "init"
}
val eventFlow = MutableStateFlow(initEvent)

不同类型的事情在 eventFlow 中流动。当遇到 flush 事情时,会将之前堆积的一切事情包装成 BatchEvent 上传网络。

这就是一个特点赋值和构建目标分开进行的场景,即一直为 BatchEvent 目标的 events 特点追加事情,直到遇到了特别事情时才构建目标:

var builder = BatchEvent.newBuilder()
eventFlow.collect { event ->
    builder.addEvent(event)
    if(event.name == "flush") {
        upload(builder.build())
        builder = BatchEvent.newBuilder()
    }
}

最终再下一个对 Builder 形式完整的总结:

  1. 为参数标示语义:在Builder形式中,每个特点的赋值都是一个函数,函数名标示了特点语义。
  2. 可选参数&分批赋值:Builder形式中,除了必选参数,其他参数是可选的,可分批赋值。而直接运用结构函数有必要一会儿为一切参数赋值。
  3. 添加参数约束条件:能够在参数不符合要求时,抛出反常。
  4. 便利实现特点赋值和结构目标的别离。
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。