用I前缀接口?

Mor*_*ten 27 tdd unit-testing dependency-injection coding-style interface

我目前正在阅读Rober Martin(UncleBob)的"清洁代码",并且一般都喜欢UncleBob的沉思.但是,当我读到他避免使用像"IPerson"这样的接口前缀时,我有点困惑.他说:"我不希望我的用户知道我正在为他们提供一个界面".

从TDD /注入角度思考,我总是非常有兴趣告诉我正在处理接口的类的"用户".主要原因是我认为接口在系统的不同"代理"之间收缩.在我的系统的一个角落工作的代理,不应该知道另一个代理工作的具体实现; 他们只应该交换合同,并期望在不知道如何履行合同的情况下履行合同.另一个但也非常重要的原因是可以完全模拟界面,从而使单元测试更容易.你可以在具体课上嘲笑多少是有限的.

因此,我更愿意想象我确实在交接接口......或者以接口作为参数.但是因为UncleBob是我们社区中的重量级冠军,而我只是另一位flyweigth桌面骑师,我想知道我是否遗漏了一些东西.

我坚持使用接口是不对的?

小智 57

我们已经习惯了Java和C#中的一些约定; 但这是倒退的.例如,从技术角度来看,将私有变量放在每个类顶部的惯例是非常愚蠢的.关于班级最重要的事情是它的公共方法.在重要的事情,我们的东西隐藏隐私屏障后面,都是实例变量.那么我们为什么要把它们放在首位呢?

接口前面的"I"是另一种向后的惯例.当您传递对对象的引用时,您应该期望它是一个接口.接口应该是默认的; 所以没有必要做一些额外的事情,比如使用我的前缀,宣布你正在做每个人都希望你做的事情.如果我们为传递具体类的异常条件保留一个特殊标记会更好(尽管仍然是错误的).

使用I的另一个问题是(奇怪地)我们使用它来传达使用接口的实现决策.通常我们不希望实施决策如此大声地表达,因为这使得它们难以改变.例如,考虑一下,如果您认为IFoo确实应该是抽象类而不是接口,可能会发生什么.您应该将名称更改为Foo或CFoo,还是ACFoo?

我能听到车轮转过头来.你在想:"是的,但界面在语言中占有特殊的位置,因此用特殊的命名约定标记它们是合理的." 确实如此.但是整数在语言中也有一个特殊的位置,我们不再标记它们(不再是).此外,问问自己,为什么界面在语言中有特殊的地位?

Java和C#中的接口背后的整个想法是一个警察.语言设计者可能刚刚使用了抽象类,但他们担心实现多重继承的困难.所以他们与自己做了一个后台交易.他们发明了一种人造结构(即接口),将提供一些多重继承的权力,他们受限正常类单继承.

这是语言设计者做出的最糟糕的决定之一.他们发明了一种新的重量级语法元素,以排除有用且功能强大(尽管有争议)的语言特性.接口不是为了启用而发明的,它们被发明为禁用.界面是设计师用语言进行的黑客攻击,他们不想解决更难的MI问题.因此,当您使用I前缀时,您将成为语言历史上最大的黑客之一的焦点.

下次你写这样的函数签名时:

public void myFunction(IFoo foo) {...}
Run Code Online (Sandbox Code Playgroud)

问自己这个:"为什么我想知道IFoo的作者使用'界面'这个词?它对我来说有什么区别,不管他是使用'界面'还是'阶级'还是'结构'? 这是他的事,不是我的! 所以他为什么要强迫我把这个伟大的我放在他的类型名称面前来了解他的事情?他为什么不把他的声明拉上来并保持他的私密性?

  • 我听到你!! 你的分数和其他分数慢慢开始影响我的脑电波.我也想知道当我放弃int和dbl和几年前的flt时,我怎么还没有放弃我. (2认同)
  • 尽管我百分百同意使用“我”是完全没有必要的,但我无法想象自己很快就会放弃这个习惯。我说不上为什么,但我喜欢这样命名接口。 (2认同)
  • 哇,强者是如何堕落的……我记得在新石器时代,当我还是一名博士生时,世界还很年轻,所有 PL 教授都对这个“解决”多重继承的新界面功能感到非常自豪,现在他们是只是一个“黑客”......我只能想到Stroustrup对他们说:“我告诉过你了”...... (2认同)
  • 当您知道它是一个接口时,您就会明白您可以传递 Foo1、Foo2 甚至 FooooF,但是当它是一个类或结构时,您只能传递 Foo,因此您应该了解作者的业务,以便使用他的代码,我不能把这当作一个严肃的论点。 (2认同)
  • 我想知道这个答案的作者是否曾经在一家大公司工作过,并发现自己处于需要修复他没有编写的代码的情况。在这种情况下,其他开发人员使用什么以及为什么使用绝对是我的事。在从事 Java 和 C#(以及 C++)方面的专业工作后,我错过了一个明确的指示,即我正在查看“我”给我的接口。这是一个非常明确的迹象,我需要更深入地研究。将“I”前缀与匈牙利表示法进行比较并不完全是同类的比较:一个告诉您数据类型,另一个暗示设计决策。 (2认同)

Krz*_*mic 9

如果你在谈论.NET,那么I一开始的接口是无处不在的,丢弃它们会让每个人都感到困惑.

另外,我更愿意

public class Foo : IFoo {}
Run Code Online (Sandbox Code Playgroud)

public class FooImpl : Foo {}
Run Code Online (Sandbox Code Playgroud)

这一切都归结为个人偏好,我自己做了一段时间玩这个想法,但我回到了I前缀.因人而异

  • 我同意sufix`Impl`很糟糕,但你可以使用别的东西.例如:我更喜欢`class SystemClock:Clock`而不是`class Clock:IClock`.甚至`类DefaultClock:Clock`.是的,我不喜欢'I`后缀. (11认同)

Mic*_*rdt 7

我认为接口在系统的不同"代理"之间收缩.在我的系统的一个角落工作的代理,不应该知道另一个代理工作的具体实现; 他们只应该交换合同,并期望在不知道如何履行合同的情况下履行合同.另一个但也非常重要的原因是可以完全模拟界面,从而使单元测试更容易.你可以在具体课上嘲笑多少是有限的.

所有这一切都是正确的 - 但它如何需要接口的命名约定?

基本上,为接口添加"I"前缀只是匈牙利符号无用的另一个例子,因为在静态类型语言中(唯一一种接口作为语言结构有意义),你总能轻松快速地找出什么是通常是在IDE中将鼠标悬停在它上面.

  • 阿门.声称I前缀有助于我理解代码就像声称句子"nounI verbAm properCumbayah"更容易理解.编程本质上是关于创建用于解决问题域的语言,而那种实现级别的混乱对该语言没有任何价值.当我们确实需要看到如此低级别的细节时,我们的工具完全能够展示它们. (6认同)
  • 我知道我可以很容易地找出类型是什么.但是,将鼠标悬停在一个类型上,以找出我正在处理的内容,对于可读性并没有太大作用,这是Clean Code中的另一个(甚至更重要的)重点.面对I-prefixed类型,我本能地知道:A)存在此接口的任意数量的实现的可能性,B)系统的其他代理可能正在使用此接口,C)出于测试目的,我可以存根/嘲笑这个合同,所以我可以诱导某些行为.所有这些我都来自一封小信.也许把这么多的意义放到我的身上是错误的? (2认同)
  • @Morten:实际上,我会说,保持技术问题的名称是你可以做的最好的可读性.您的ABC积分都是客户端代码不应该关心的技术实现细节. (2认同)