不变树的生成器模式

时间:2018-06-26 20:11:42

标签: tree kotlin immutability

我正在尝试在Kotlin中创建一个AST来描述正则表达式(这是基于2016年的一些现有研究:http://regex.inginf.units.it/)。

我已经写了所有的运算符和操作数,而我想要做的是在Kotlin中使用internal关键字来封装树结构的所有讨厌的不可变属性,然后使用构建器模式来为我将要使用的一些算法公开一棵漂亮的不可变树(使用多态类型从可变->不可变属性进行映射)。

以下是包含可变属性var parent: Node?

的内部类
internal interface Node {
    var parent: Node?
    fun describe() : String
    fun isValid() : Boolean
    fun isCharClass() : Boolean = false
    fun isEscaped() : Boolean = false
}

internal abstract class AbstractNode(protected val children: Collection<Node>,
                                 override var parent: Node? = null) : Node

internal interface Leaf : Node

这是我想从此模块中公开的主要数据结构(注意:主要区别是父节点的不变性)

interface ImmutableNode {
    val parent: ImmutableNode?
    fun describe() : String
    fun isValid() : Boolean
    fun isCharClass() : Boolean = false
    fun isEscaped() : Boolean = false
}

我偏爱的API模式是构建器模式。因此,我创建了一个用于构建树的界面,如下所示:

interface ImmutableSyntaxTreeFactory {
    fun build(): ImmutableSyntaxTree
    fun addNode(node: Node) : ImmutableSyntaxTreeFactory
}

interface ImmutableSyntaxTree : ImmutableNode

interface ImmutableNode {
    val parent: ImmutableNode?
    fun describe() : String
    fun isValid() : Boolean
    fun isCharClass() : Boolean = false
    fun isEscaped() : Boolean = false
}

通过ImmutableNode(可变变种)构造Node如下:

internal fun buildFrom(from: Node?) : ImmutableNode? {
        return when(from) {
            null -> null
            else -> {
                object : ImmutableNode {
                    override val parent = buildFrom(from::parent.invoke())
                    override fun describe() = from::describe.invoke()
                    override fun isValid() = from::isValid.invoke()
                    override fun isCharClass() = from::isCharClass.invoke()
                    override fun isEscaped() = from::isCharClass.invoke()
                }
            }
        }
    }

现在,问题来了。 addNode接口上的immutableSyntaxTreeFactory方法需要内部Node接口作为依赖项。显然这是行不通的。对于初学者-它不会编译!我必须使Node成为非内部的(才能编译它),这将暴露parent的可变Node属性,打破了我封装可变性的所有希望和梦想。

但是,如果我通过ImmutableNode ...好,那就是鸡肉和鸡蛋。如果我必须构造ImmutableNode才能传递给公共API,那为什么还要麻烦底层的可变表示(实际上,在我要进行各种各样的操作时,也需要有可变的底层表示)从子树等中重建树)。

所以,我想知道让构建器模式采用enum类型(以暴露可能的可变运算符集)以及var args String类型作为可能集是否有意义并让构建器决定要在幕后构建哪些可变运算符,然后将其多态映射到不可变节点。是否有不可变的树构建器模式的出色示例?

编辑:进行澄清; ImmutableNode需要不可变子类型通过将可变类型的公共属性映射到相应的不可变类型属性来镜像可变类型。例如,我有AbstractNode的可变子类型,这些子类型具有内部受保护的子级集合,这些子类型通过公共属性公开,例如operand(对于一元运算符),leftOperandrightOperand (对于二进制运算符),以及firstOperandsecondOperandthirdOperand(对于燕尾运算符)。这些将需要映射到相应的不可变类型,因为它们最终都将从Node(具有可变的父属性)继承。

我只是从问题中漏掉了它,因为它不相关。

0 个答案:

没有答案