【问题标题】:Are there established alternatives to ISomething / ISomethingable for interfaces?接口是否有 ISomething / ISomethingable 的替代方案?
【发布时间】:2008-10-21 16:11:03
【问题描述】:

在接口名称前加上 I 前缀的 .NET 标准似乎越来越普遍,并且不再仅限于 .NET。我遇到过很多使用这种约定的 Java 代码(所以如果 Java 在 C# 之前使用它,我不会感到惊讶)。 Flex 也使用它,等等。不过,在名称的开头放置一个 I 有点匈牙利符号的味道,所以我对使用它感到不舒服。

所以问题是,是否有另一种表示Something 是接口而不是类的方法,并且无论如何都需要这样表示它。还是它成为一个标准,所以我应该接受它并停止试图通过建议以不同的方式来挑起“宗教战争”?

【问题讨论】:

  • 这实际上在java中被认为是不好的做法。请参阅 Joshua Bloch 的 Effective Java。这很棒,但 C# 仍然在使用它,这也是相当可悲的。
  • @drozzy,(或任何阅读它的人)——你还记得 J.Bloch 在哪里讨论过这个话题(我的意思是页面)吗?我有这本书的第二版,我找不到任何关于“I”命名约定的参考。
  • @greenoldman 好点,他实际上并没有说它“坏”,只是没有提及。见第237-238 有效 Java 第 2 版。对不起我的过分热心。

标签: naming-conventions interface


【解决方案1】:

来自《框架设计指南》一书:

表示层次结构根的接口(例如 IList)也应该使用名词或名词短语。表示能力的接口应该使用形容词和形容词短语(例如 IComparable、IFormattable)。

另外,来自接口命名的注释:

KRZYSZTOF CWALINA:少数人之一 接口使用的前缀是“I” (如在 ICollection 中),但这是为了 历史原因。回想起来,我 认为使用会更好 常规类型名称。在大多数 案例开发人员不在乎 某物是一个接口而不是一个 例如抽象类。

BRAD ABRAMS:另一方面,接口上的“I”前缀很明确 承认 COM 的影响 (和 Java)在 .NET Framework 上。通讯 普及化,甚至制度化, 接口开始的符号 用“我”。虽然我们讨论过 背离这一历史模式 我们决定发扬光大 就像我们的许多用户一样 已经熟悉 COM。

JEFFREY RICHTER:就个人而言,我喜欢 “我”前缀,我希望我们有更多 像这样的东西。小一字 前缀对保留有很长的路要走 代码简洁但具有描述性。正如我 前面说过,我使用前缀 私有类型字段,因为我发现 这个很有用。

BRENT RECTOR 注意: 这真的是另一个应用 匈牙利符号(虽然没有 符号的缺点 在变量名中使用)。

它已成为一种广泛采用的标准,虽然它是匈牙利语的一种形式,正如 Brent 所说,但它没有在变量名中使用匈牙利符号的缺点。

【讨论】:

  • 哇,这些人真聪明。我尤其是布拉德·艾布拉姆斯的忠实粉丝。
【解决方案2】:

说实话,我会接受它。我知道你说的有点像匈牙利符号(或至少滥用相同)是什么意思,但我认为在这种情况下它有足够的价值值得做。

随着依赖注入的流行,我经常发现我最终得到了一个接口和一个单一的生产实现。只需使用 I 前缀即可轻松区分它们。

一个小数据点:我经常使用 Java 和 C#,而且我经常发现自己必须检查 Java 中的哪些类型实际上是接口,尤其是在集合框架周围。 .NET 让这一切变得简单。也许它不会打扰其他人,但它会打扰我。

我为 IFoo +1。

【讨论】:

  • 我不明白为什么这么多人发现通过类型命名将接口与其他类型区分开来很有用。现代 IDE 会在文件名旁边放置一个漂亮的图标。此外,如果您不熟悉该类型,您可能需要打开它并阅读源代码/文档。
  • @i3ensays:“文件名旁边”假设您正在包浏览器或其他任何地方查看它。我宁愿在阅读代码时不必采取任何行动。是的,我可以查找所有内容,但我宁愿不查找。这绝对是一件主观的事情,但我喜欢 .NET 的约定。
  • 这可能取决于您的文本编辑器/IDE,但代码内智能感知可以很好地处理我的区别。例如,当我在声明分配时键入“new”时,我可以自动完成分配,所有已知的实现类型都显示在子上下文菜单中。
  • @i3ensays:那是你编写代码的时候。我花更多的时间阅读代码而不是编写代码......而且很多时间都花在差异视图等而不是 IDE 上。
【解决方案3】:

作为 .NET 程序员(在大多数情况下),我实际上更喜欢在此处删除 I 的 Java 约定,原因很简单:通常,小的重新设计需要从接口更改为抽象基类或反之亦然。如果您必须更改名称,这可能需要进行大量不必要的重构。

另一方面,客户端的使用应该是透明的,所以他们不应该关心这种类型的提示。此外,“Thingable”中的“able”后缀应该足够暗示了。它在 Java 中运行良好。

/EDIT:我想指出,上述推理促使我放弃了私人项目的I 前缀。然而,根据 FxCop 规则集检查其中一个后,我立即恢复使用I即使a foolish consistency is the hobgoblin of little minds,一致性在此获胜。

【讨论】:

  • 这太糟糕了......当一致性开始决定编程实践时,这是一个滑坡。
  • @drozzy:一致性总是决定了编程实践。而“滑坡”的说法是一个逻辑谬误。事实上,如果你想为一种编程语言设计一个可重用的 API,你就是在迎合期望。 API 应该易于使用,这意味着它应该与用户已经知道的一致。有个理由违反此规则,但类名前面的愚蠢I 不是其中之一。我认为微软的命名约定很愚蠢,但火车已经离开了车站。
  • API 中的一致性更符合我的喜好。当您想与其他 API 保持一致时,我同意,您必须遵守。但是,如果您正在独立从事一个项目,并且始终放弃 I 前缀,为什么不呢?事实上,为什么不教新手程序员放弃它……
  • @drozzy:嗯,每个 .NET 项目都使用 .NET 框架 API。并且使用I 作为接口前缀。此外,没有一个真正的项目是完全独立于其他项目的,迟早项目可能会变得如此之大,以至于需要与其他现有 API 进行交互。并且每个代码都应该写成未来证明,因为你永远不知道这些代码将来是否会在其他地方使用,或者是否需要与外部代码交互。 .NET 框架基本上规定了在其他 .NET 项目中使用的所有基本约定。
  • 我确实在徘徊,如果微软的人决定不在 .net 5.0 中使用它会发生什么。
【解决方案4】:

一切都与风格可读性有关。在接口前加上“I”只是一种流行的命名约定和风格指南。编译器本身并不在意。

【讨论】:

  • 一般来说匈牙利符号确实如此。它只是人类阅读代码的命名约定。编译器不关心变量的名称,只要它们是唯一命名的并且只使用有效的符号。
【解决方案5】:

我的主要假设是,最重要的是保持实现的领域部分的可读性。因此:

  • 如果你有一种行为和一种可能的实现,那么就不要创建接口:

    public class StackOverflowAnswerGenerator { }

  • 如果你有一个行为和许多可能的实现,那么没有问题,你可以去掉“I”,然后:

    public interface StackOverflowAnswerGenerator {}

    public class StupidStackOverflowAnswerGenerator : StackOverflowAnswerGenerator {}

    public class RandomStackOverflowAnswerGenerator : StackOverflowAnswerGenerator {}

    public class GoogleSearchStackoverflowAnswerGenerator : StackOverflowAnswerGenerator {}

    //...

  • 真正的问题是当您有一种行为和一种可能的实现,但您需要一个接口来描述其行为(例如,为了方便测试,由于项目中的约定,使用一些强制执行此操作的库/框架,.. .)。可能的解决方案,除了为接口添加前缀之外,还有:

    a) 为实现添加前缀或后缀(如本主题的其他一些答案所述)

    b)为接口使用不同的命名空间:

    namespace StackOverflowAnswerMachine.Interfaces 
    {
      public interface StackOverflowAnswerGenerator {}
    }
    
    namespace StackOverflowAnswerMachine 
    { 
      public class StackOverflowAnswerGenerator : Interfaces.StackOverflowAnswerGenerator
    {}
    
    }
    

    c)使用不同的命名空间来实现:

    namespace StackOverflowAnswerMachine 
    {
      public interface StackOverflowAnswerGenerator {}
    }
    
    namespace StackOverflowAnswerMachine.Implementations 
    { 
      public class StackOverflowAnswerGenerator : StackOverflowAnswerMachine.StackOverflowAnswerGenerator 
    {}
    
    }
    

尽管我认为最后一种可能性是最干净的,但它的一个缺点是即使using StackOverflowAnswerMachine; 允许您访问所有域对象,您也必须为所有域接口添加前缀,以免与它们的实现混淆。这可能感觉不是很方便,但在干净的设计中,通常一个类不使用许多其他域对象,并且大多数情况下您只需要在字段声明和构造函数参数列表中使用前缀。所以,这是我目前的建议。

领域功能的客户不需要知道他们使用的是接口、抽象类还是具体类。如果他们需要知道这一点,那么在这样的项目中就会出现一些严重的问题,因为它在同一个抽象层上混合了领域逻辑和基础设施问题。因此我推荐“a”或“c”解决方案。

【讨论】:

    【解决方案6】:

    Symbian 的编码标准具有用 M 而不是 I 表示的接口(纯抽象 C++ 类)。

    否则,我见过的表示接口的唯一其他方式是通过上下文。

    【讨论】:

      【解决方案7】:

      对于.NET,微软的框架设计指南书绝对推荐它,是的,它非常标准。我从来没有见过这样的做法,创建一个新的公约只会让人感到困惑。

      我应该补充一点,我也不喜欢匈牙利表示法,但是这种情况以及在类变量前加下划线的情况对我来说是一个很好的例外,因为它们使代码更具可读性。

      【讨论】:

      • 在 C++ 中以 _ 为前缀的类变量让我很恼火。 _ 表示系统变量和库,而不是类变量。
      • 对于 C++,我同意你的看法。我特别喜欢它们用于 C#。
      【解决方案8】:

      我一直认为这种命名约定有点像恐龙。如今,IDE 已经足够强大,可以告诉我们某物是一个接口。补充一点,我会使代码更难阅读,所以如果你真的想要一个将接口与类分开的命名约定,我会将 Impl 附加到实现类的名称中。

      public class CustomerImpl implements Customer
      

      【讨论】:

      • 但是我们怎么知道 Customer 是一个接口而不是一个抽象类呢?
      • 我认为“Impl”后缀使代码比接口上的“I”前缀更难阅读,尤其是对于面向公众的 API。
      • @RobertS。你为什么在乎?认真的。
      • @ScottDorman 有些人可能会提到包中的排序顺序列表(实现可能会紧随接口之后),但我同意,后缀很讨厌,宁愿看到添加到前缀名称的实现细节(例如 PremiumCustomer)
      【解决方案9】:

      您要求另一种选择,所以这是我遇到的一种:

      在接口类上使用 no 前缀,但在相应的具体类上使用 cC 前缀。您的大多数代码通常会引用接口,所以为什么要使用前缀而不是通常使用较少的具体类型来污染它。

      这种方法确实引入了一个不一致之处,即某些具体类型将被添加前缀(具有匹配接口的类型)而其他类型则不会。这可能很有用,因为它提醒开发人员存在接口,并且应该优先使用它而不是具体类型。

      说实话,在界面上使用了前缀,但我认为更多的是因为我已经习惯和习惯了它。

      【讨论】:

        猜你喜欢
        • 2021-04-07
        • 1970-01-01
        • 2014-01-29
        • 1970-01-01
        • 2020-10-07
        • 2012-09-02
        • 2016-08-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多