我想创建一个框架,用户可以在其中创建基类Node
的子类,该基类能够根据当前实例状态生成消息(此处为整数),以及另一个实例的属性(参数n)。用户应该能够专门化方法getMessage
以根据当前实例的类和参数n 的类生成不同的消息,如下面的代码所示。
函数importantAlgorithm
使用这些节点生成的消息来计算最终结果。
// Classes defined by the framework //
abstract class Node {
def getMessage(n: Node) : Int
}
def importantAlgorithm(lstNodes1: List[_ <: Node], lstNodes2: List[_ <: Node]) = {
val results = lstNodes1.zip(lstNodes2).map({case (n1, n2) =>
// I would like to get the proper message *BASED ON
// THE TYPE OF N1 and N2*
val message = n1.getMessage(n2)
// Do some work with the message
//...
//...
})
//...
}
// Classes defined by framework users //
class ItemNode(val p: Int) extends Node {
override def getMessage(n: UserNode) = {
// Compute message based on this ItemNode member variables
// and n (instance of UserNode) member variables
}
override def getMessage(n: ItemNode) = {
// Compute message based on this ItemNode member variables
// and n (instance of UserNode) member variables
// The algorithm is different from the algorithm
// used in the previous method
}
}
class UserNode extends Node {
override def getMessage(n: OtherNode) = {
// Compute message. Same idea as above
}
}
class OtherNode extends Node {
override def getMessage(n: UserNode) = {
// Compute message. Same idea as above
}
}
// The user should be able to use the framework this way
importantAlgorithm(List(new UserNode(), new ItemNode(236), new OtherNode(),
List(new OtherNode(), new ItemNode(542), new UserNode()))
当然,Scala不允许在子类中专门化方法的参数,并且上面的代码不能编译。我可以使用isInstanceOf[]
或RTTI,但我感觉我没有正确思考而没有正确设计我的框架。 如何通过更简单,更清晰的解决方案替换上面代码示例中描述的机制?
答案 0 :(得分:1)
我认为你需要的是像
trait Node {
type AppropriateSender <: Node
def getMessage(n: AppropriateSender): Int
}
class UserNode extends Node {
type AppropriateSender = OtherNode
def getMessage(n: OtherNode) = ???
}
...
但是,类型擦除会导致一些问题,因此您无法检查n1
和n2
(可能是类型标记?)的兼容性,但至少可以在现在干净的方式。另一个问题是如何处理某些节点类型具有多于1个适当的发送方类型的事实(可能通过raw union type的实现来解决)。
答案 1 :(得分:1)
这样就够了吗? (它编译......)
/* Classes defined by the framework */
abstract class Node {
def getMessage(n: Node): Int
}
def importantAlgorithm(lstNodes1: List[Node], lstNodes2: List[Node]) {
lstNodes1.zip(lstNodes2).map {
case (n1, n2) =>
// I would like to get the proper message *BASED ON
// THE TYPE OF N1 and N2*
val message = n1.getMessage(n2)
}
}
/* Classes defined by framework users */
class ItemNode(val p: Int)
extends Node
{
def getMessage(n: Node): Int =
n match {
// Compute message based on this ItemNode member variables
// and n (instance of UserNode) member variables
case un: UserNode => 0
case in: ItemNode => 1
case xn: Node => -1
}
}
class UserNode
extends Node
{
def getMessage(n: Node): Int =
n match {
case on: OtherNode => 23
case xn: Node => -1
}
}
class OtherNode
extends Node
{
def getMessage(n: Node): Int =
n match {
case xn: Node => 514
}
}
// The user should be able to use the framework this way
importantAlgorithm(List(new UserNode(),
new ItemNode(236),
new OtherNode()),
List(new OtherNode(),
new ItemNode(542),
new UserNode()))