Kotlin中的生成器模式

Kotlin中的生成器模式,kotlin,Kotlin,我是科特林世界的新手。我有一个用Java编写的现有构建器,并希望在将项目迁移到Android中的Kotlin时将其转换为Kotlin。然而,Android Studio内置工具似乎有一些bug,然后转换的代码是不可编译的。它显示myUserBuilder类中的变量无法访问 下面是来自 自动转换的kotlin代码: class Person private constructor(builder: UserBuilder) { val firstName: String // requir

我是科特林世界的新手。我有一个用Java编写的现有构建器,并希望在将项目迁移到Android中的Kotlin时将其转换为Kotlin。然而,Android Studio内置工具似乎有一些bug,然后转换的代码是不可编译的。它显示my
UserBuilder
类中的变量无法访问

下面是来自

自动转换的kotlin代码:

class Person private constructor(builder: UserBuilder) {
    val firstName: String // required
    val lastName: String // required
    val age: Int // optional
    val phone: String // optional
    val address: String // optional

    init {
        //cannot access the variables, they are private in UserBuilder
        this.firstName = builder.firstName  
        this.lastName = builder.lastName   
        this.age = builder.age
        this.phone = builder.phone
        this.address = builder.address
    }

    class UserBuilder(private val firstName: String, private val lastName: String) {
        private var age: Int = 0
        private var phone: String? = null
        private var address: String? = null

        fun age(age: Int): UserBuilder {
            this.age = age
            return this
        }

        fun phone(phone: String): UserBuilder {
            this.phone = phone
            return this
        }

        fun address(address: String): UserBuilder {
            this.address = address
            return this
        }

        fun build(): Person {
            return Person(this)
        }

    }
}

更新

class Person private constructor(builder: UserBuilder) {
    val firstName: String // required
    val lastName: String // required
    val age: Int // optional
    val phone: String? // optional
    val address: String? // optional

    init {
        this.firstName = builder.firstName
        this.lastName = builder.lastName
        this.age = builder.age
        this.phone = builder.phone
        this.address = builder.address
    }

    class UserBuilder(internal val firstName: String, internal val lastName: String) {
        internal var age: Int = 0
        internal var phone: String? = null
        internal var address: String? = null

        fun age(age: Int): UserBuilder {
            this.age = age
            return this
        }

        fun phone(phone: String): UserBuilder {
            this.phone = phone
            return this
        }

        fun address(address: String): UserBuilder {
            this.address = address
            return this
        }

        fun build(): Person {
            return Person(this)
        }

    }
}

只需像以前一样进行简单的转换

现在您将看到,
UserBuilder
将具有
internal
access修饰符,只需删除该修饰符并添加public或任何您需要的内容即可


编辑1 好的,
internal
关键字不在您的
Kotlin
代码中,我在检查代码时忽略了这一点

所以现在您需要做的是在
Person
类中创建一个对象,并将
UserBuilder
类放在其中

检查以下代码:

class Person private constructor(builder: Builder.UserBuilder) {
    val firstName: String // required
    val lastName: String // required
    val age: Int // optional
    val phone: String // optional
    val address: String // optional

init {
    //cannot access the variables, they are private in UserBuilder
    this.firstName = builder.firstName  
    this.lastName = builder.lastName   
    this.age = builder.age
    this.phone = builder.phone
    this.address = builder.address
}
object Builder {
class UserBuilder(private val firstName: String, private val lastName: String) {
    private var age: Int = 0
    private var phone: String? = null
    private var address: String? = null

    fun age(age: Int): UserBuilder {
        this.age = age
        return this
    }

    fun phone(phone: String): UserBuilder {
        this.phone = phone
        return this
    }

    fun address(address: String): UserBuilder {
        this.address = address
        return this
    }

    fun build(): Person {
        return Person(this)
    }

}
}
}
这应该像在Java代码中一样工作


希望它能有所帮助。

考虑到它是Kotlin,您实际上可以使用数据类将其简化得多

data class User(val firstName: String, 
        val lastName: String,
        val age: Int = 0,
        val phone: String? = null,
        val address: String? = null)
就这样!前两个参数是必需的,但如果要指定更多参数,只需按名称指定:

val user = User("John", "Doe", phone = "555-1212")
不需要建筑工人

class Person private constructor(builder: UserBuilder) {
val firstName: String // required
val lastName: String // required
val age: Int // optional
val phone: String // optional
val address: String // optional

init {
    this.firstName = builder.firstName  
    this.lastName = builder.lastName   
    this.age = builder.age
    this.phone = builder.phone
    this.address = builder.address
}

class UserBuilder(private val _firstName: String, private val _lastName: String) {
    private var _age: Int = 0
    private var _phone: String? = null
    private var _address: String? = null

    var firstName: String
        get() = this._firstName
    var lastName: String
        get() = this._lastName
    var age: Int = 0
        get() = this._age
    var phone: String? = null
        get() = this._phone
    var address: String? = null
        get() = this._address

    fun age(age: Int): UserBuilder {
        this._age = age
        return this
    }

    fun phone(phone: String): UserBuilder {
        this._phone = phone
        return this
    }

    fun address(address: String): UserBuilder {
        this._address = address
        return this
    }

    fun build(): Person {
        return Person(this)
    }

}
}


以这种方式使用自定义getter可以解决私有访问修饰符问题。

您好,谢谢您的帮助。我知道kotlin有可选的params支持,但我仍然希望有builder,因为我的kotlin库将在Java中使用。这并不能真正取代builder模式。@抗坏血酸取决于您需要builder做什么。如果您需要捕获一个生成器引用并直接使用它,那么这可能不适合您。如果您只是使用构建器从Java端提供默认值和/或简化构造函数,那么这实际上是一种替代。另外,请看一看如何使用@JVMLowloads构造函数生成Java中所需的每个构造函数排列,如果您同意从Java构建器更改为只调用单个构造函数,那么您的解决方案似乎仍然不适合我。它显示了相同的可访问性错误。最后,我将
UserBuilder
中的实例变量更改为internal,以便
Person
访问它。我忘了提到该方法将从其他模块调用。我已经检查了上面的代码,它可以从不同的模块正常工作。如果您遗漏了什么,请重新检查。一个与另一个相结合是一个糟糕的建筑设计。如果您能提供更好的想法,我很想看看它在Kotlin的工作原理,因为我是Kotlin世界的新手。很抱歉,我使用手机,我认为KCopock的答案满足您的需求。我说的是:“
User
不应该依赖于
UserBuilder
”,:)
class Person private constructor(builder: UserBuilder) {
val firstName: String // required
val lastName: String // required
val age: Int // optional
val phone: String // optional
val address: String // optional

init {
    this.firstName = builder.firstName  
    this.lastName = builder.lastName   
    this.age = builder.age
    this.phone = builder.phone
    this.address = builder.address
}

class UserBuilder(private val _firstName: String, private val _lastName: String) {
    private var _age: Int = 0
    private var _phone: String? = null
    private var _address: String? = null

    var firstName: String
        get() = this._firstName
    var lastName: String
        get() = this._lastName
    var age: Int = 0
        get() = this._age
    var phone: String? = null
        get() = this._phone
    var address: String? = null
        get() = this._address

    fun age(age: Int): UserBuilder {
        this._age = age
        return this
    }

    fun phone(phone: String): UserBuilder {
        this._phone = phone
        return this
    }

    fun address(address: String): UserBuilder {
        this._address = address
        return this
    }

    fun build(): Person {
        return Person(this)
    }

}