不可变类中的方法继承

时间:2014-02-04 18:29:25

标签: scala design-patterns inheritance traits

我对某些事情感到磕磕绊绊,我希望这是一个基本问题。可能是因为我是Scala的新手,可能我仍然缺少一些重要的概念。

我正在尝试以FP方式编程,并且不需要具有可变状态的数据类是不可变的,使用一些转换方法来创建新对象以在需要时更新它们。但是,当我有特征和一般继承时,我在维护这个方法的返回类型时遇到了困难。我希望尽可能地避免混乱的类型演员或类似的事情,因为这对我来说仍然是一种学习经历。

在这里看到这个例子,我有一个不可变的类扩展了一些特征。 update方法旨在更改数据,调用实际类的某些方法(在特征中是抽象的),并将更新的同一类的新实例返回到新数据。可以粗略地将其映射到模板模式。

trait MyTrait
{
   val someDataVal : Integer;

   def update(newDataVal) : MyTrait = {
     //some logic takes place here, which is common

     abstractUpdate(newDataVal)
   }

   //some logic takes place, specific to the implementation class
   def abstractUpdate(newDataVal : Integer) : MyTrait
}


class MyClass(dataVal : Integer) extends MyTrait
{
   override val someDataVal = dataVal

   def abstractUpdate(newDataVal : Integer) : MyClass = {
     //some class specific logic here ........

     MyClass(newDataVal)
   }

   def someOtherFunction() : Integer = { 
     //some logic here .....
   }
 }

我显然不希望将update()复制并粘贴到MyClass我希望它保留在特征中,以便我可以在任何扩展它的类中使用它。但是,如果我尝试调用它,我得到的是MyTrait类型的对象,因此我无法在其上调用someOtherFunction()

什么是正确的Scala方法来实现这种OO重用并仍然保持我的代码清洁?

更新

请注意我放置//some logic takes place here的地方,这意味着我可能在那里有一些代码,我希望将其集中在特征中,而不是复制和粘贴到扩展它的每个具体类中。这只是解释问题的骨架。谢谢你的时间。

更新

基于小麦提供的答案的代码示例。问题出在return this

trait MyTrait[T <: MyTrait[T]]{
  def update(newValue: Int): T = {
    if (newValue == 0)
      return this;  //this creates a type mismatch
    else
      concreteUpdate(newValue)
  }

  def concreteUpdate(value : Int) : T
}

class MyClass(value: Int) extends MyTrait[MyClass]
{
  override def concreteUpdate(value : Int) = new MyClass(value)
}

1 个答案:

答案 0 :(得分:3)

之前我已经回答了类似的问题,@ GaborBakos发表了评论。如果您希望能够使用map TraverseableLike方法找到类似的内容,那么您需要执行以下操作:

trait MyTrait[T <: MyTrait[T]]{
  def update(newValue: Int): T
}

基本上是一个依赖于自身的类型定义!因此,update的返回类型为T。然后:

class MyClass(value: Int) extends MyTrait[MyClass]{
  def update(newValue: Int) = new MyClass(newValue)
}

应该有效,因为TMyClass

旁注:

不要将val置于特质中。相反,将其设为def。这样,您就不会遇到想要扩展您的类的任何人的初始化排序问题。如果您不遵循此建议,那么您可能会遇到非null字段被视为null的情况。