假设我们有两个类,Foo
和Bar
。
Bar
应该只能从Foo
对象构造。
这是我目前的尝试,原因是我不认为它们是适当的解决方案:
尝试1:
class Foo {
var data: Int = 0 // meh: This implementation detail should not be exposed to the public.
fun add(x: Int) {
data += x
}
}
class Bar(foo: Foo) {
private var data: Int = 2 * foo.data
fun show() = println(data + 10)
}
fun main() {
val myFoo = Foo()
myFoo.add(3)
myFoo.add(4)
val myBar = Bar(myFoo)
myBar.show()
}
问题:Foo::data
从外面不可见。
尝试2:
class Foo {
private var data: Int = 0
fun add(x: Int) {
data += x
}
fun makeBar() = Bar(2 * data)
}
class Bar(private val data: Int) { // meh: Bar should only be instantiated from a Foo.
fun show() = println(data + 10)
}
fun main() {
val myFoo = Foo()
myFoo.add(3)
myFoo.add(4)
val myBar = myFoo.makeBar()
myBar.show()
}
问题:每个人现在都可以创建Bar
,即使手头没有Foo
。
来自C ++的第一个解决方案是将Bar
的构造函数设为私有,但通过声明其为friend
类仅让Foo
对其进行访问。在Kotlin中是否可能有类似的事情,或者还有另一种(更好的)解决方案?
答案 0 :(得分:4)
阅读用例之后,您可能正在寻找inner class。这是从您尝试使用内部类Bar
得出的解决方案:
class Foo {
private var data = 0 // private as you do not want to make it publicly available
fun add(x: Int) {
data += x
}
inner class Bar {
private var data = 2 * this@Foo.data // access the outer foo directly... no need to hold it in the constructor
fun show() = println(data + 10)
}
}
fun main() {
val myFoo = Foo()
myFoo.add(3)
myFoo.add(4)
// val myBar = Foo.Bar() // this does not compile... you need a foo to build a bar...
val myBar = myFoo.Bar() // this works...
myBar.show()
// myBar.data // this wouldn't compile as it's not accessible
}
正如您所说,您更喜欢顶级课程。根据您希望Foo.data
的安全程度,您可能还会对以下设置感兴趣:
class Foo {
private var data = 0
fun add(x: Int) {
data += x
}
fun Bar.getFooData() = data
}
class Bar(foo: Foo) {
private var data = 2 * with(foo) { getFooData() }
fun show() = println(data + 10)
}
因此,只有在Bar
和Foo
都可用时(后者作为接收者),您才可以访问Foo的数据。但是,这也意味着,如果两个对象均可用,则您可以从外部访问Foo.data
。以下在main
中也将成功:
with (myFoo) {
myBar.getFooData()
}
所以:让data
不能从外部访问(忽略反射),嵌套类或内部类是您的朋友。使其难以访问(或:在使用前强制某些条件成立),带有适当接收者的扩展功能方法可能是您的朋友。