具有Traits的Scala客户端组合与实现抽象类

kli*_*iew 33 abstract-class scala traits abstract

我已经阅读过Scala,通常建议使用Traits而不是Abstract类来扩展基类.

以下是一个很好的设计模式和布局吗?这是Traits如何取代Abstract?

  • 客户端类(使用def function1)
  • trait1类(覆盖function1)
  • trait2类(覆盖function1)
  • specificClient1使用trait1扩展客户端
  • specificClient2使用trait2扩展客户端

Tra*_*own 67

我不知道你的源代码是什么声称你应该更喜欢Scala中的抽象类的特征,但有几个原因不能:

  1. 特征使Java兼容性变得复杂.如果您有一个伴随对象的特征,则从Java调用伴随对象上的方法需要奇怪的MyType$.MODULE$.myMethod语法.具有伴随对象的抽象类不是这种情况,伴随对象在JVM上作为具有静态和实例方法的单个类实现.使用Java中的具体方法实现Scala特性更令人不愉快.
  2. 将具有实现的方法添加到特征会破坏二进制兼容性,从而不会向类添加具体方法.
  3. 特征导致更多的字节码和一些与使用转发器方法相关的额外开销.
  4. 特征更强大,这很糟糕 - 通常你想要使用功能最弱的抽象来完成工作.如果你不需要它们支持的那种多重继承(通常你不需要),最好不要访问它.

到目前为止,最后一个原因是我认为最重要的原因.在未来的Scala版本中,至少还有一些其他问题可能会得到解决,但是默认情况下,默认情况下,以类似于(至少可以证明)与良好设计一致的方式约束您的程序.如果你确定你真的真的想要特质提供的力量,他们仍然会在那里,但这将是你做出的决定,而不是你只是陷入其中.

所以不,在没有其他信息的情况下,我建议使用抽象类(理想情况下是密封的)和两个提供实现的具体类.

  • 作为一个脚注,Scala的线性化方法是多重继承"问题"的巧妙解决方案,当你需要它时它运行得很好(除了像字段这样的一些东西).但是你永远不应该因为它聪明而使用某些东西. (2认同)
  • 使用Scala [2.12](http://www.scala-lang.org/news/2.12.0)时,#1-3仍适用于vis-a-vis`“特性使用默认方法直接编译到接口上。这改善了二进制兼容性和Java互操作性。” 我相信,当然#4足以选择“特质”而不是“抽象类”。@TravisBrown (2认同)