【问题标题】:Scala's naming convention for traitsScala 对特征的命名约定
【发布时间】:2013-06-15 08:44:27
【问题描述】:

假设我在 Scala 中有一个 trait

trait Connection {

  def init(name: String)
  def dispose
}

我想创建一个实现它的类。但我也想将其命名为Connection

class Connection extends Connection {
  // ....
 }

这是行不通的。当然,我可以将trait 命名为不同的名称,但事实证明,Scala 中的命名约定说我应该将 trait 命名为普通类,这意味着没有任何前缀,我将在 C# 中使用它(IConnection where @987654327 @ 将是 interface)。

在这种特殊情况下,classtrait 的名称为 Connection 更合适。

还是我错过了 Scala 命名约定中的某些内容?

【问题讨论】:

    标签: scala


    【解决方案1】:

    您将通用 API 提取到 Connection 特征中的事实本身意味着它将具有多个特定实现。这些实现当然会与一些更具体的实体相关,例如MySQL 或 H2 数据库。

    根据您选择的应用架构,有几种方法可以解决您的问题:

    1. 如果你将特定的实现保留在你得到的同一个命名空间中:

      • myApp.Connection

      • myApp.MySqlConnection

      • myApp.H2Connection

    2. 但由于名称冗余(*Connection 部分),实际上不鼓励上述内容,建议引入新包,例如:

      • myApp.Connection

      • myApp.connections.MySql

      • myApp.connections.H2

      • myApp.Connection

      • myApp.Connection.MySql

      • myApp.Connection.H2

      如果您选择将特定实现放在Connection伴随对象中。

    3. 在更高级的架构方法中,您最终会得到具有私有包的特定实现:

      • myApp.Connection

      • myApp.mySql.Connection

      • myApp.h2.Connection

      即使在这里,尽管 Connection 名称冲突,但由于类型位于不同的包中,使用限定引用 (myApp.Connection) 或限定导入很容易解决:

      import myApp.{Connection => GeneralConnection} //or IConnection if you insist
      

    【讨论】:

    • 我认为选项 1 在实践中是最常见的。当您阅读代码时,选项 2 会令人困惑。
    • @monkjack 没错;可能感觉像是在重复相同的信息,但另一方面,您不能指望所有开发人员都拥有所有类型的所有包上下文
    【解决方案2】:

    这不是约定,但 scala.collection 中使用的东西是后缀 Like 用于特征:

    • SeqLike:Seq[A] 类型序列的模板特征。
    • MapLike:映射的模板特征,它将键与值相关联。

    等等。

    我猜这是他们说 Rectangle/Rectangular 的方式,其中这种关系 (Seq/SeqLike) 没有明确的命名。

    【讨论】:

      【解决方案3】:

      在 Martin Odersky 的书中有一个示例,其中包含扩展特征 Rectangular 的类 Rectangle 和扩展特征 Ordered 的类 Rational。所以这里的模式似乎是对特征名称使用形容词,对类名称使用主题。因此,在您的情况下,它将是“类连接扩展连接”。至少我比“class ConnectionImpl extends Connection”更喜欢这个。

      【讨论】:

      • 也许连接扩展了可连接。它可能并不总是连接。
      【解决方案4】:

      命名实现某些接口/特征的类的常见做法是将Impl添加为后缀(并且不要向接口/特征添加任何前缀/后缀):

      class ConnectionImpl extends Connection {
        // ....
      }
      

      为什么?因为在良好的代码中你 write functions against interfaces,所以你不会用那些 I 来污染你的函数:

      def sendThings(conn: Connection) {
      
      
      }
      

      对比

      def sendThings(conn: IConnection) {
      
      
      }
      

      如果你有多个实现,这当然应该是Connection trait、HttpConnection class1、JdbcConnection class2。

      【讨论】:

      • HttpUtilImpl, UserImpl, CarImpl...?也就是说,我应该在代码中的每个类名中添加Impl,即使没有具有相似名称的特征?一点都不合理。
      • @MariusKavansky 不,只有当存在 trait 和 one class 的情况并且它们的名称没有区别时。
      • 那是一回事。正如我在问题中所说,我可以用不同的方式命名特征(或类),但我不想那样做。
      • Martin Odersky 在他的书中有一个 Rectangular 特征的示例,其中 Rectangle 类扩展了 Rectangular 特征。我喜欢这个 Rectangle->Rectangular 命名对。我想要的是一个命名约定,它是 Rectangle->Rectangular 的概括。但这很难找到。对我来说,使用 Impl 的解决方案是丑陋的。我也不喜欢 Java 世界。
      • +1 链接,并在代码的“私有/隐藏”部分而不是“公共”部分添加额外的词缀。
      猜你喜欢
      • 1970-01-01
      • 2019-10-13
      • 2016-04-17
      • 2015-05-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多