首页 > 解决方案 > 可扩展层次结构的类构建器模式(弱 ADT)

问题描述

TL;博士

给定案例类的层次结构,可以构造实例树:

2021-02-25 更新

我可以让它以某种方式工作

import org.scalajs.dom.console

trait Root
case class Bob(name: String, as: Seq[Root]) extends Root
case class Charles(value: Int, as: Seq[Root]) extends Root


trait Builder[T] {
  // can not make T covariant, as this is obj is not in a covariant position
  def build(obj: T) : String
}

object Foo {
  var r: Map[Root, Builder[Root]] = Map()
  def attachBuilder[T <: Root](a: T, builder: Builder[T]) : Unit = {
    val e = (a, builder)
    r = r + e.asInstanceOf[(Root, Builder[Root])]
  }

  def b(name : String, as: Root*)(implicit builderB: Builder[Bob]): Bob = {
    val b = Bob(name, as)
    attachBuilder(b, builderB)
    b
  }

  def c(value: Int, as: Root*)(implicit builderC: Builder[Charles]): Charles = {
    val c = Charles(value, as)
    attachBuilder(c, builderC)
    c
  }

  def build(obj: Root) : String = {
    r(obj).build(obj)
  }
}

object UseMe {

  implicit val builderB: Builder[Bob] = new Builder[Bob] {
    override def build(obj: Bob): String = {
      obj.name.toString + obj.as.map(a => Foo.build(a)).mkString(" ")
    }
  }

  implicit val builderC: Builder[Charles] = new Builder[Charles] {
    override def build(obj: Charles): String = {
      obj.value.toString + obj.as.map(a => Foo.build(a)).mkString(" ")
    }
  }

  def yahoo() : Unit = {
    val x = Foo.b("martin", Foo.b("b2"), Foo.c(127))
    console.log("This is x: " + Foo.build(x))
  }
}

尽管如此,我还是很不满意。想法,我遵循:有一张地图,可以捕捉到 Bob 或 Charles 各自的建造者。仍然,

要求

问题

原帖

序幕

叹息....令人费解的浪费时间........我真的需要你的帮助!

设想

给定一个 ADT

trait A
case class B(name: String, as: Seq[A]) extends A
case class C(value: Int, as: Seq[A]) extends A

预计会延长(未密封)。

此外,假设一个

trait Builder[T] {
  def build(obj: T) : String
}

此外,通过下面的代码,我们有“创建者函数”,期望适当的构建器在范围内。

object Foo {
  def b(name : String, as: A*)(implicit builderB: Builder[B]): B = {
    ???
    // How to link ADT instance B with builder for B in a type-safe manner?
    // How to trigger builder for `as`: Seq[A] ?
  }

  def c(value: Int, as: A*)(implicit builderC: Builder[C]): C = {
    ???
    // How to link ADT instance C with builder for C in a type-safe manner?
  }
}

有了这个,我希望能够,在将适当的构建器定义为隐式 valsBC

object UseMe {
  implicit val builderB: Builder[B] = new Builder[B] {
    override def build(obj: B): String = {
      obj.toString
      // and build the as
    }
  }

  implicit val builderC: Builder[C] = new Builder[C] {
    override def build(obj: C): String = {
      obj.value.toString
      // and also build the as
    }
  }

  val x = Foo.b("martin", Foo.b("b2"), Foo.c(127))

  // Questions
  // How to create a string representation (that is what the builder is doing) for x
  // Something like:
  // build(x)
}

有意地,我删除了我在代码中的所有误导性尝试,也不是为了引起任何偏见。

尝试

问题

期待您的回答!

标签: scalagenericsbuilderimplicit

解决方案


推荐阅读