用相同的方法混合特征和基类

时间:2019-01-16 13:12:43

标签: scala inheritance traits base-class

我可以安全地继承具有相同方法的特征和基类吗?

赞:

trait MyTrait {
   def getValue:String
}

class SomeClass {
   def getValue:String = [concrete implementation]
}

然后:

class MyClass extends SomeClass with MyTrait

这样做的原因是我想在另一个(抽象)类中使用它,该类仅通过MyTrait特征来定义所需的API,而我不能让SomeClass继承此特征直接(因为它来自另一个不相关的库)。

abstract class AbstractOtherClass {
   val mainObject:MyTrait
}

然后是该类的具体实现:

class OtherClass extends AbstractOtherClass {
   val mainObject:MyTrait = new MyClass

   def something = {
      println(mainObject.getValue)  // shall call SomeClass.getValue
   }
}

解决方案
在SergGr的建议之后,我最终得到了这样的解决方案:

abstract class AbstractOtherClass {
   def getValue:String
}

class OtherClass extends AbstractOtherClass {
   val mainObject:SomeClass = ...

   def getValue:String = mainObject.getValue
}

1 个答案:

答案 0 :(得分:1)

这里似乎有两个不同的问题

  1. 这项工作仅仅是偶然发生的吗?
  2. 这是一个好的设计吗?

只要您的trait仅声明了方法但没有实现,则它是设计使然的。这是不寻常但预期的使用模式之一。如果多个traittraitclass具有相同方法的实现,则linearization仍将有一个明确指定的逻辑,该逻辑指定如何解决冲突,但是我会说,在大多数情况下,依靠它是一个糟糕的设计。

您尝试做的事情对我来说像adapter pattern,我想说从设计的角度来看,最好使用对象组合而不是继承来实现它。

trait MyTrait {
   def getValue:String
}

class SomeClassWrapper(delegate: SomeClass) extends MyTrait {
    override def getValue:String = delegate.getValue       
}

通过这种方式,您不会将API绑定到库的实现。例如,如果在上下文中更有意义,则可以将方法重命名为getAbcValue值。或者,如果您在某个时候找到另一个库,它的性能更好,但该方法的名称不同(例如calculateValue),则只需创建另一个包装器类,而不必更改所有getValue个呼叫到calculateValue个呼叫。