用同样的方法混合 trait 和 base class

Mixing trait and base class with same method

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

喜欢:

trait MyTrait {
   def getValue:String
}

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

然后:

class MyClass extends SomeClass with MyTrait

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

abstract class AbstractOtherClass {
   val mainObject:MyTrait
}

然后是那个class的具体实现:

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. 这项工作仅仅是偶然的吗?
  2. 这样的设计好吗?

只要您的 trait 只有方法声明而没有实现,它就可以正常工作。这是一种不寻常但符合预期的使用模式。如果几个 trait 或一个 trait 和一个 class 有相同方法的实现,仍然有一个明确指定的逻辑 linearization 指定如何解决冲突但是我会说在大多数情况下依赖它是一个糟糕的设计。

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

trait MyTrait {
   def getValue:String
}

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

这样做你不会将你的 API 绑定到库的实现。例如,如果这在您的上下文中更有意义,您可以将该方法重命名为 getAbcValue 值。或者,如果你在某个时候找到另一个库,它可以更好地完成相同的工作,但对这种方法有不同的名称(比如 calculateValue),你必须创建另一个包装器 class 而没有将所有 getValue 调用更改为 calculateValue 调用。