【问题标题】:How to keep track of dependencies with immutable design?如何使用不可变设计跟踪依赖关系?
【发布时间】:2016-06-14 05:46:35
【问题描述】:

当对象之间存在依赖关系时,以功能方式设计软件的方法是什么?

class Link(val name: String, val links: Vector[Link] = Vector()){

    def changeName(newName: String): Link = {
        new Link(newName, links)
    }

    def connect(other: Link): Link = {
        new Link(name, links :+ other)
    }
}

object Main
{
    def main(args: Array[String]): Unit = {
            val A = new Link("A")
            val B = new Link("B")
            val Alinked = A connect B 
            val updatedB = B changeName "B2"
            println(Alinked.links.contains(updatedB))
    }
}

输出

我连接了 A 和 B,但随后 B 正在更改。这意味着,我必须将新对象重新连接到以前的对象。在复杂的层次结构中,很难控制此类更新。

如何进行自动重新链接?代表?演员?

【问题讨论】:

    标签: scala functional-programming immutability


    【解决方案1】:

    如果您需要将对象的不可变副本的身份保持在一起,我认为一种解决方案是引入唯一标识符:

    case class Link(id: Int)(val name: String, val links: Vector[Link] = Vector()) {
      def changeName(newName: String): Link =
        new Link(id)(newName, links)
    
      def connect(other: Link): Link =
        new Link(id)(name, links :+ other)
    }
    
    def test(): Boolean = {
      val A         = Link(0)("A")
      val B         = Link(1)("B")
      val Alinked   = A connect B 
      val updatedB  = B changeName "B2"
      Alinked.links.contains(updatedB)
    }
    
    assert(test())
    

    也就是说,一旦创建了一个对象,您将在所有副本中携带相同的id。这里的case class 确保通过查看id 字段来正确定义equals

    【讨论】:

    • 所以基本上没有办法重新发明指针并将当前状态保持在Map[Id, Any]?
    • 好吧,你可以使用双向链接,然后connect 必须同时更新接收器和源。但是,是的,每个步骤都需要一份状态副本。如果您想要一种不可变但并发安全的更简单方法,我建议使用 STM(软件事务内存)。 Scala 有一个非常好的库
    • @0__ 有没有办法让静态指针始终指向类的最后一个实体?
    • @CronAcronis 不,因为那时你基本上回到了可变设计,只是更复杂。我认为双向图和相互依赖本质上很难以不可变的方式维护。如果您的代码从不同时运行,您不妨只使用可变结构。正如我所说,也看看STM。还有scala-graph
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-01
    • 2015-06-06
    • 2021-01-13
    • 1970-01-01
    相关资源
    最近更新 更多