【问题标题】:Dynamic binding for two arguments两个参数的动态绑定
【发布时间】:2020-11-13 16:21:09
【问题描述】:

这个问题涉及静态类型语言中的设计模式,尤其是动态绑定(我在这里使用 Kotlin,但也可以是 C++ 或 Java)。问题如下:我有一个接口Node(代表Ast中的节点)和多个元素的串联(有多个这样的类)。

interface Node {
    fun concat(next: Node): Node {
        return Concat(listOf(this, next))
    }
}

class Concat(val nodes: List<Node>): Node {
}

我现在想确保 Concat 始终是扁平的,即没有一个节点是串联的。使用if(next is Concat) 类型检查会很容易,但我想使用动态绑定并避免此类类型检查。我的第一次失败的解决方案尝试如下:

interface Node {
    fun concat(next: Node): Node {
        return next.reverseConcat(this)
    }

    fun reverseConcat(prev: Node): Node {
        return Concat(prev, this)
    }
}

class Concat(val nodes: List<Node>): Node {
    override fun concat(next: Node): Node {
        // TODO what if next is a Concat?
        return Concat(nodes + next)
    }

    override fun reverseConcat(prev: Node): Node {
        // TODO what if prev is a Concat?
        return Concat(listOf(prev) + nodes) 
    }
}

但是如果两个节点都是 Concat 的实例,这将失败。另一种解决方案尝试是添加reverseConcat-methods 和Concat 作为参数。

interface Node {
    // ...
    fun reverseConcatWithConcat(nextNodes: List<Node>): Node {
        return Concat(listOf(this) + nextNodes)
    }
}

class Concat(val nodes: List<Node>): Node {
    override fun concat(next: Node): Node {
        return next.reverseConcatWithConcat(nodes)
    }

    override fun reverseConcat(prev: Node): Node {
        // TODO what if prev is a Concat?
        return Concat(listOf(prev) + nodes) 
    }

    fun reverseConcatWithConcat(nextNodes: List<Node>): Node {
        return Concat(nodes + nextNodes)
    }
}

这会起作用,但它会使接口变得混乱(考虑到还有其他节点,类似于 Concat),并且它还留下了接口中没有受保护的方法的问题,因此 reverseConcat 仍然很危险。

有没有更令人满意的方法使用动态绑定,不会不必要地混乱代码?

【问题讨论】:

    标签: oop kotlin design-patterns polymorphism dynamic-binding


    【解决方案1】:

    通常我会做这样的事情,因为它是高性能的(虽然我会提供多连接):

    interface Node {
        fun forContents(proc: (Node) -> Unit) {
            proc(this)
        }
        // I don't actually like this signature, but it's what you wanted
        fun concat(next: Node) : Node {
            val list = ArrayList<Node>()
            forContents(list::add)
            next.forContents(list::add)
            return Concat(list)
        }
    }
    
    class Concat(val contents: List<Node>) : Node {
        override fun forContents(proc: (Node) -> Unit) {
            contents.forEach(proc)
        }
    }
    

    你也可以这样做:

    interface Node {
        val contents: List<Node> get() = listOf(this)
        
        fun concat(next: Node) : Node = Concat(
            listOf(this.contents, next.contents).flatten()
        )
    }
    
    class Concat(override val contents: List<Node>) : Node {
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-12
      • 2019-08-24
      • 2012-06-04
      相关资源
      最近更新 更多