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

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

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

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

【问题讨论】:

    标签: scala abstract-class abstract traits


    【解决方案1】:

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

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

    在我看来,最后一个原因是迄今为止最重要的。在 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 服务器可能会使用从数据服务器更新的同一对象的只读版本。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-06-04
      • 1970-01-01
      • 2011-03-03
      • 1970-01-01
      • 2013-01-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多