在Scala中,如何使用隐式转换将方法“添加”到公共父级的子类中?

时间:2019-04-11 01:03:18

标签: scala polymorphism implicit-conversion

假设我在“哑巴”模型中有一些数据。在此示例中,我将使用message.mentionsCircle,它们扩展了Triangle

我正在寻找一种隔离可能使用这些形状的行为的方法,但是我不确定构造它的最佳方法。如果我想将这些形状绘制到文档上,则希望能够编写如下所示的代码:

trait Shape

这里的窍门是shapes.foreach(doc.add) shapesSeq[Shape]方法是我想隐式添加的东西,因为我自己不能修改形状(我也不想将这些特定功能纳入其中)。

我遇到的困难是,我不知道如何将隐式转换与子类混合使用。有关更多信息,请参见下面的代码中的add

QUESTION:

我确定要查找的名称有个名字,但我只是不知道它是什么或要搜索的内容。

1 个答案:

答案 0 :(得分:2)

问题:编译器无法选择和使用特定于处理子类的隐式值。当您仅知道它是Triangle时,根本无法决定要调用哪种方法(对于CircleShape)。这实际上是一个经典问题,具有标准解决方案。

解决方案1 ​​

DocumentExtension.add内的模式匹配

优点:

  1. 由于您的trait Shape被定义为sealed,如果您错过某个祖先的案例,编译器将为您提供帮助。
  2. 分离类定义和动作处理

缺点:

  1. 样板必须列出您的特征的所有子类

解决方案2

经典访客模式

sealed trait Shape {
  def addToDoc(doc: Document, visitor: ShapeDrawer)
}
final class Triangle extends Shape {
  def addToDoc(doc: Document, visitor: ShapeDrawer) = visitor.draw(doc, this)
}
final class Circle extends Shape {
  def addToDoc(doc: Document, visitor: ShapeDrawer) = visitor.draw(doc, this)
}

trait ShapeDrawer {
  def draw(doc: Document, t: Circle)
  def draw(doc: Document, t: Triangle)
}

val drawer: ShapeDrawer = ???
val doc: Document = ???
val shapes = Seq.empty[Shape]

shapes.foreach(_.addToDoc(doc, drawer))

此解决方案还符合在编译时确保已处理Shape的每个子类的要求,但是需要向trait本身添加奇怪的方法。