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

Posted

技术标签:

【中文标题】具有 Traits 的 Scala 客户端组合与实现抽象类【英文标题】:Scala client composition with Traits vs implementing an abstract class 【发布时间】:2016-05-16 22:48:23 【问题描述】:

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

以下是一个好的设计模式和布局吗?这就是 Traits 打算取代 Abstract 的方式吗?

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

【问题讨论】:

【参考方案1】:

我不知道您声称您应该更喜欢 Scala 中的特征而不是抽象类的说法的来源是什么,但有几个原因

    特性使 Java 兼容性复杂化。如果你有伴生对象的特征,从 Java 调用伴生对象上的方法需要奇怪的 MyType$.MODULE$.myMethod 语法。对于带有伴生对象的抽象类,情况并非如此,它们在 JVM 上作为具有静态和实例方法的单个类来实现。在 Java 中使用具体方法实现 Scala trait 更加令人不快。 将具有实现的方法添加到 trait breaks binary compatibility 的方式与向类添加具体方法的方式不同。 特征会导致更多字节码和一些与使用转发器方法相关的额外开销。 特征更强大,这很糟糕——通常,您希望使用最不强大的抽象来完成工作。如果您不需要他们支持的那种多重继承(而且您通常不需要),最好不要访问它。

在我看来,最后一个原因是迄今为止最重要的。在 Scala 的未来版本中,至少还有几个其他问题might get fixed,但默认使用类仍会以与良好设计一致的方式(至少可以说)限制您的程序。如果你决定你真的确实想要特质提供的力量,它们仍然会在那里,但这将是你做出的决定,而不是你随便溜进去的东西。

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

【讨论】:

作为脚注,Scala 的线性化方法对多重继承“问题”的巧妙解决方案,当你需要它时它工作得很好(除了一些东西,比如字段)。但是你不应该仅仅因为它很聪明就使用它。 谢谢,这回答了我的问题。我的来源是safaribooksonline.com/library/view/scala-cookbook/9781449340292/…。不过你的回答更有意义 使用 Scala 2.12 时,#1-3 是否仍然适用于 "A trait compiles directly to an interface with default methods. This improves binary compatibility and Java interoperability."?当然,我相信 #4 有足够的理由选择 abstract class 而不是 trait。 @TravisBrown Travis,你有什么建议让特质更强大吗?【参考方案2】:

OTOH,特征允许您以精细的方式构建和测试复杂对象的功能,并重用核心逻辑以提供不同的风格。例如,域对象可能会部署到数据服务器,该数据服务器会持久保存在数据库中,而 Web 服务器可能会使用从数据服务器更新的同一对象的只读版本。

没有什么东西适合所有场景。为手头的任务使用正确的结构。有时,实现的现实会暴露出设计时未知的特定用例的问题。使用不同的假设和构造重新实现可能会产生令人惊讶的结果。

【讨论】:

以上是关于具有 Traits 的 Scala 客户端组合与实现抽象类的主要内容,如果未能解决你的问题,请参考以下文章

Scala学习之TRAITS和抽象类

Scala语法详解:特质 (Traits)

PHP多继承实现--Traits

PHP的学习--Traits新特性

Traits vs. Interfaces vs. Mixins?

具有不同生命周期的对象的 Scala 蛋糕模式