Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oop 我可以在不知道上下文的情况下更新嵌套很深的不可变对象吗?_Oop_Kotlin_Immutability - Fatal编程技术网

Oop 我可以在不知道上下文的情况下更新嵌套很深的不可变对象吗?

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) {

假设我有一个嵌套的不可变对象图,大致如下(使用Kotlin语法,但希望清楚):

现在,我想打开水壶。如果对象是可变的,我会写:

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以可重复使用的方式从一个家到另一个水壶,我喜欢。但为了更新水壶,我仍然需要了解水壶的完整结构。没有办法将关注点定位到水壶自己的方法。除非我缺少一些关于镜头的东西?