替换子类中方法参数的特化

时间:2013-02-14 18:02:07

标签: scala polymorphism

我想创建一个框架,用户可以在其中创建基类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,但我感觉我没有正确思考而没有正确设计我的框架。 如何通过更简单,更清晰的解决方案替换上面代码示例中描述的机制?

2 个答案:

答案 0 :(得分:1)

我认为你需要的是像

trait Node {
  type AppropriateSender <: Node
  def getMessage(n: AppropriateSender): Int
}

class UserNode extends Node {
  type AppropriateSender = OtherNode
  def getMessage(n: OtherNode) = ???
}

...

但是,类型擦除会导致一些问题,因此您无法检查n1n2(可能是类型标记?)的兼容性,但至少可以在现在干净的方式。另一个问题是如何处理某些节点类型具有多于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()))