假设我在“哑巴”模型中有一些数据。在此示例中,我将使用message.mentions
和Circle
,它们扩展了Triangle
。
我正在寻找一种隔离可能使用这些形状的行为的方法,但是我不确定构造它的最佳方法。如果我想将这些形状绘制到文档上,则希望能够编写如下所示的代码:
trait Shape
这里的窍门是shapes.foreach(doc.add)
是shapes
,Seq[Shape]
方法是我想隐式添加的东西,因为我自己不能修改形状(我也不想将这些特定功能纳入其中)。
我遇到的困难是,我不知道如何将隐式转换与子类混合使用。有关更多信息,请参见下面的代码中的add
。
QUESTION:
我确定要查找的名称有个名字,但我只是不知道它是什么或要搜索的内容。
答案 0 :(得分:2)
问题:编译器无法选择和使用特定于处理子类的隐式值。当您仅知道它是Triangle
时,根本无法决定要调用哪种方法(对于Circle
或Shape
)。这实际上是一个经典问题,具有标准解决方案。
解决方案1
DocumentExtension.add
内的模式匹配
优点:
trait Shape
被定义为sealed
,如果您错过某个祖先的案例,编译器将为您提供帮助。缺点:
解决方案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本身添加奇怪的方法。