Oop 我可以在不知道上下文的情况下更新嵌套很深的不可变对象吗?
假设我有一个嵌套的不可变对象图,大致如下(使用Kotlin语法,但希望清楚): 现在,我想打开水壶。如果对象是可变的,我会写:Oop 我可以在不知道上下文的情况下更新嵌套很深的不可变对象吗?,oop,kotlin,immutability,Oop,Kotlin,Immutability,假设我有一个嵌套的不可变对象图,大致如下(使用Kotlin语法,但希望清楚): 现在,我想打开水壶。如果对象是可变的,我会写: data class Kettle(var on: Boolean) { fun activate() { this.on = true } } house.kitchen.kettle.activate() 但因为它们是不可变的,我不得不写: data class Kettle(val on: Boolean) {
data class Kettle(var on: Boolean) {
fun activate() {
this.on = true
}
}
house.kitchen.kettle.activate()
但因为它们是不可变的,我不得不写:
data class Kettle(val on: Boolean) {
fun activate(house: House): House {
return house.copy(kitchen = kitchen.copy(kettle = kettle.copy(on = true)))
}
}
house = house.kitchen.kettle.activate(house)
(实际上,它稍微复杂一些,但是这个伪代码就可以了)
我不喜欢这个,不是因为它本身很长,而是因为水壶现在不仅需要知道它自己的内部状态,还需要知道它存在的完整环境
我如何重写它,使每个对象都能负责提供自己的变异逻辑,而不必知道完整的对象图?或者我只是想以一种不可能的方式将面向对象和功能概念结合起来?我想到的一种可能的方法(顺便提一下,这就是提问者)是这样的:
data class Kettle(val on: Boolean) {
fun activate() {
return Transform(this, Kettle(on = true))
}
}
class Transform<T>(val what: T, val replacement: T) {
fun <U> apply(x: U): U {
if (x is T && x == what) {
return replacement as U
} else {
return x
}
}
}
val transform = house.kitchen.kettle.activate()
house = house.transformEverything(transform)
data class House(val bedroom: Bedroom, val bathroom: Bathroom, val kitchen: Kitchen) {
fun transformEverything(transform: Transform): House {
return transform(this).copy(
bedroom = bedroom.transformEverything(transform),
bathroom = bathroom.transformEverything(transform),
kitchen = kitchen.transformEverything(transform)
)
}
}
每个类都有这样的实现:
data class Kettle(val on: Boolean) {
fun activate() {
return Transform(this, Kettle(on = true))
}
}
class Transform<T>(val what: T, val replacement: T) {
fun <U> apply(x: U): U {
if (x is T && x == what) {
return replacement as U
} else {
return x
}
}
}
val transform = house.kitchen.kettle.activate()
house = house.transformEverything(transform)
data class House(val bedroom: Bedroom, val bathroom: Bathroom, val kitchen: Kitchen) {
fun transformEverything(transform: Transform): House {
return transform(this).copy(
bedroom = bedroom.transformEverything(transform),
bathroom = bathroom.transformEverything(transform),
kitchen = kitchen.transformEverything(transform)
)
}
}
它递归地给变换一个机会来修改它想要修改的每个对象,并且它只将它应用于一个对象
这种方法不好,因为:
数以吨计的锅炉板为每件事物提供了自己的transformEverything
方法的哑版
必须对图形中的每个对象调用函数来更改一个对象,这似乎很奇怪(而且效率很低)
但它确实实现了我的目标,即水壶不需要知道任何有关其上下文的信息,而且编写activate
函数非常简单。思想?这是功能镜片显示其力量的地方。比如,
我想你要求的代码行(在天真的方法上)是:返回房子。复制(厨房=房子。厨房。复制(水壶=房子。厨房。水壶。复制(on=true))
是的,这就是我说的在现实中更复杂的意思-这个例子有点简单我认为你可以通过添加打开水壶来实现(或者沿着这条路走)去房子
,然后让它通过更换水壶
来创建自己的新形象。虽然这可能会限制你的代码,因为每个厨房
都必须有一个水壶
嗨,我看了功能镜片,但我看不出它们对我有什么帮助。镜头让我简单地描述一下pa以可重复使用的方式从一个家到另一个水壶,我喜欢。但为了更新水壶,我仍然需要了解水壶的完整结构。没有办法将关注点定位到水壶自己的方法。除非我缺少一些关于镜头的东西?