class需要是抽象的,因为trait中的方法没有定义错误

时间:2017-10-17 15:40:12

标签: scala class object inheritance traits

假设我们有一个基类(trait),它有两个方法(同名,不同的参数,而不是实现):

trait Base {
    def compute(arg1:type1, arg2:type2): returnType
    def compute(arg1:type1, arg2:type2, arg3:type3): returnType
}

我们有一些继承自Base的类。假设它们是A,B,C,A和B实现"计算"有两个args,而C实现"计算"有三个参数。

class A  extends Base {
    def compute(arg1:type1, arg2:type2): returnType = {
        //detailed implementations
    }
}

class B  extends Base {
    def compute(arg1:type1, arg2:type2): returnType = {
        //detailed implementations
    }
}

class C  extends Base {
    def compute(arg1:type1, arg2:type2, arg3:type3): returnType = {
        //detailed implementations
    }
}

现在,我有一组这些对象objs,我想自动选择哪个版本的"计算"使用:

val name = objs.map{ x =>
    val name = x.getClass.getSimpleName
    name match {
        case "C": x.compute(arg1, arg2, arg3)
        case _: x.compute(arg1, arg2)
    }
}

然而,它编译错误:

class A(B the same) needs to be abstract, since method compute in trait Base of type (three parameters) is not defined

我对此错误感到困惑。这是因为Base中的所有方法都必须在其子类(A,B,C)中实现吗?

在没有编辑A类和B类的情况下是否有任何优雅的修复(因为C类是最近设计的,它的compute必须再添加一个参数,所以我再设计了一个函数)?

3 个答案:

答案 0 :(得分:1)

您需要在compute(arg1:type1, arg2:type2, arg3:type3)A中定义B并在compute(arg1:type1, arg2:type2)中定义C,否则您可以提供默认值,无操作在你的特质中实现

trait Base {
    def compute(arg1:type1, arg2:type2) {}
    def compute(arg1:type1, arg2:type2, arg3:type3) {}
}

我还建议在Base

中明确定义返回类型

修改

使用案例类的完整(简化)工作示例:

trait Base {
  def compute(arg1: Int, arg2: Int): Int = 0
  def compute(arg1: Int, arg2: Int, arg3: Int): Int = 0
}

case class A() extends Base {
  override def compute(arg1: Int, arg2: Int): Int = arg1 + arg2
}

case class B() extends Base {
  override def compute(arg1: Int, arg2: Int): Int = arg1 - arg2
}

case class C() extends Base {
  override def compute(arg1: Int, arg2: Int, arg3: Int): Int = arg1 + arg2 - arg3
}

case class D(arg1: Int, arg2: Int, arg3: Int, objs: Seq[Base]) {
  val computed = objs map (_ match {
    case x: C    => x.compute(arg1, arg2, arg3)
    case x: Base => x.compute(arg1, arg2)
  })
}

答案 1 :(得分:1)

您是否听说过界面隔离原则

  

接口隔离原则(ISP)声明没有客户端应该   被迫依赖它不使用的方法。1 ISP分裂   接口非常大,更小,更具体   客户只需了解其中的方法   对他们感兴趣。这种缩小的界面也称为角色   接口

来源:Wikipedia

Traits在某些方面类似于名为“interfaces”的那些。

基本上,你必须分开Base特质 Traits代表Scala中的模块,将它们保持在较小状态是一种很好的做法,这样我们就可以提高它们的组合能力并获得更大的抽象。

你最终会得到两个特征: (我只是将命名改为更清楚)

trait Computation {
  def compute(arg1:Int, arg2:Int): Unit
}

trait SpecificComputation {
  def compute(arg1:Int, arg2:Int, arg3:Int)
}

class A extends Computation {
  def compute(arg1:Int, arg2:Int) = {
    //detailed implementations
  }
}

class B  extends Computation {
  def compute(arg1:Int, arg2:Int) = {
    //detailed implementations
  }
}

class C extends SpecificComputation {
  def compute(arg1:Int, arg2:Int, arg3:Int) = {
    //detailed implementations
  }
}

如果您想要了解这两个class D方法变体的compute,请写下:

class D extends SpecificComputation with Computation {

      def compute(arg1:Int, arg2:Int) = {
        //detailed implementations
      }

      def compute(arg1:Int, arg2:Int, arg3:Int) = {
        //detailed implementations
      }
}

答案 2 :(得分:1)

同意@ Mik378。但是,如果您正在从2 args版本迁移到3 args版本,您可以:

trait Base {
  // Mark this as deprecated
  // No default implementation here because otherwise, A & B would need to 
  // be modified to add the 'override' keyword
  @deprecated
  def compute(arg1:type1, arg2:type2): returnType

  // Provide a default implementation for old implementations e.g. A / B
  def compute(arg1:type1, arg2:type2, arg3:type3): returnType =
    compute(arg1, arg2)
}

// Convenience base class for new implementations e.g. C
abstract class NewBase extends Base {
  override def compute(arg1: type1, arg2: type2): returnType =
    throw new UnsupportedOperationException
}

class A  extends Base {
  def compute(arg1:type1, arg2:type2): returnType = {
    //detailed implementations
  }
}

class B  extends Base {
  def compute(arg1:type1, arg2:type2): returnType = {
    //detailed implementations
  }
}

// All new implementations extend 'NewBase' instead of 'Base'
class C  extends NewBase {
  override def compute(arg1:type1, arg2:type2, arg3:type3): returnType = {
    //detailed implementations
  }
}

现在,您只需使用3-args版本即可获得旧版和版本版。新的objs,

val name = objs.map(_.compute(arg1, arg2, arg3))