界面命名约定
这当然是一个主观的东西,但是我没有看到用“I”加接口名称前面的任何东西。 对我而言, Thing
实际上总是比IThing
更可读。
我的问题是,为什么这个惯例存在呢? 当然,它可以更容易地告诉来自其他types的接口。 但是,这种争论不会延续到保留现在被广泛谴责的匈牙利表示法吗?
你觉得那个尴尬的“我”是什么意思? 或者更重要的是,微软有什么用?
公约(以及对他们的批评)都有其背后的理由,所以让我们来看看公约背后的一些原因吧
-
接口以I为前缀来区分接口types和实现 – 例如,如上所述,需要一个简单的方法来区分
Thing
和它的接口IThing
所以这个约定就是为此而服务的。 -
接口是前缀我来区分它与抽象类 – 当您看到下面的代码时有歧义:
public class Apple: Fruit
没有约定,人们不知道
Apple
是从另外一个名为Fruit
类inheritance的 ,还是如果它是一个名为Fruit
的接口的实现 ,而IFruit
会使这一点变得很明显:public class Apple: IFruit
最小惊喜原则适用。
-
并非匈牙利符号的所有用法都受到指责 – 匈牙利符号的早期使用表示前缀,表示对象的types,然后在variables名称前面加上variables名称或有时是下划线。 对于某些编程环境(Visual Basic 4 – 6)来说,这是有用的,但是随着真正的面向对象编程的普及,指定types变得不切实际和冗余。 在智能感知方面,这成为了特别的问题。
今天匈牙利符号是可以接受的区分UI元素从实际数据和类似的相关联的UI元素,例如文本框的
lblObject
,与该文本框关联的标签的lblObject
,而文本框的数据只是Object
。我还必须指出,匈牙利符号的原始使用不是用于指定数据types(称为系统匈牙利符号),而是指定variables名称(称为“应用匈牙利符号”)的语义使用。 在匈牙利语法的维基百科条目上阅读更多内容。
那么,一个明显的考虑就是(非常常见的) IFoo
和Foo
对(当抽象Foo
),但是更一般地说,知道某个接口和类是否是一个接口是非常重要的。 是的,它是部分多余的,但IMO是不同的东西像sCustomerName
– 在这里,名称本身( customerName
)应该足以理解variables。
但是用CustomerRepository
– 它是一个类还是抽象接口?
另外:期待; 事实是,对与错,这是人们所期望的。 这几乎是足够的理由。
我这样做的原因很简单:因为这是惯例。 我宁愿按照它,而不是所有的代码看起来不同,使阅读和学习更难。
Thing
比IThing
更可读的名字。 我从思想stream派来看,我们应该编写接口而不是具体的实现。 所以一般来说,接口应该优先于实现。 我更喜欢给接口更可读的名称,而不是实现(即我的接口被命名为不带'I'前缀)。
我觉得比在你的具体课上增加一个“Impl”后缀更好。 这是一封单一的信,而且这个惯例已经确立。 当然你可以自由使用你想要的任何命名。
在我看来,这个“我”只是视觉噪音。 IDE应该以不同的方式显示类和接口名称。 幸运的是Java标准库不使用这个约定。
没有什么不对的使用I惯例的接口 – 只要一致,并确保它不仅适用于你,而且适用于整个团队(如果有的话)。
我相信你的问题是Microsoft团队内部长时间讨论.NET框架及其标准的主题。
我认为最有说服力的例子来自源头本身。 下面,我转录从框架devise指南 ,我强烈推荐的书摘录。
CLR项目经理Krzysztof Cwalina表示:
唯一使用的前缀是“我”的接口(如
ICollection
),但这是历史原因。 回想起来,我认为使用常规types名称会更好。 在大多数情况下,开发人员并不关心某些东西是接口而不是抽象类。
从Brad Abrams,CLR和.NET Framework程序经理:
另一方面,接口上的“I”前缀清楚地认识到COM(和Java)对.NET Framework的影响。 COM普及化,甚至制度化,接口以“I”开始的符号。 虽然我们讨论了与这个历史模式不同的地方,但是我们决定继续推进这个模式,因为我们的许多用户已经熟悉了COM。
来自Jeffrey Richter,顾问兼作者:
就个人而言,我喜欢“我”的前缀,我希望我们有更多这样的东西。 小的单字符前缀在保持代码简洁而又具有描述性的方面有很长的路要走。 […]我使用我的私人types字段的前缀,因为我觉得这非常有用。
我的意思是,这是在讨论桌上。 我看到的一个好处是,它有助于避免类和接口之间的名称冲突,所以你的名字可以是描述性的和紧凑的
就个人而言 – 也许出于习惯 – 我喜欢I
前缀,因为它简洁地标记了接口,使我能够与实现types进行一一对应的命名对应。 当你想要提供一个base
实现的IThing
是很明显的: IThing
是接口, Thing
是基础(可能是abstract
)types。 派生types可以是SomeThing
。 我喜欢能够使用如此清晰的速记符号。
因为你通常有一个IThing 和一个事情。 因此,不要让人们在这种反复出现的情况下出现自己的“惯例”,而是select一种统一的,一劳永逸的惯例。 回应别人的话,事实上的标准是足够的理由来使用它。
请用字母I来表示接口名称,以表明该types是一个接口。
指南并没有解释为什么你应该使用I
前缀,但事实是,这是一个既定的公约应该是足够的理由。
通过删除I
前缀,您有什么收获?
这只是一个约定,意图是防止名称冲突。 C#不允许我有一个名为Client的类和接口,即使文件名分别是Client和IClient。 我很习惯使用这个约定。 如果我必须提供一个不同的约定,我build议使用“Contract”作为后缀,例如ClientContract。
我不知道他们为什么select这个惯例,也许部分考虑用“我”这个“我是无数的”这个“我”来保护这个class级。
在框架的其余部分可能更多的命名约定是将types包含在名称中,例如xxxAttribute和xxxException类,使其成为xxxInterface。 虽然这有点冗长,毕竟接口是独立的,而不仅仅是一堆类。
从类中分离接口
另外(这更像是个人观察,而不是从高处指定),接口描述了一个class级所做的事情。 '我'适合这个(我相信这是一个语法结构,现在可以很好地鞭打)。 描述validation的类将是“IValidate”的接口。 描述匹配行为的将是“IMatch”。
我知道微软的指导方针build议使用'我'来描述它作为一个接口。 但是,如果我没有记错的话,这来自IBM的命名约定,为接口启动“I”,为实现启动成功的* Impl。
然而,在我看来,Java命名约定是比IBM命名约定更好的select(不仅在Java中,在C#中也在任何OO编程语言中)。 接口描述了一个对象如果实现接口能够做什么,描述应该是动词forms。 即运行,序列化,发票等。恕我直言,这是一个完美的界面代表的描述。
OS GUI对于文件和文件夹使用不同的图标很受欢迎。 如果他们共享相同的图标,但文件夹前缀为“F”,则可以使用相同的图标。 但是,由于人类的图像识别速度比他们的文字识别速度快,所以我们已经确定了图标。
像IDE这样的计算机程序完全可以使文件的界面变得明显。 这将释放不同级别抽象的命名空间以相同的名称发生。 例如在“ICare”中,“I”描述了实现,“Care”描述了接口的function。
我猜“我”的惯例是如此受欢迎,因为我们还没有想到更好的东西,但它的存在是非常重要的,因为它指出了我们需要知道这种信息。
它看起来对我来说是匈牙利语 。 匈牙利语通常被认为是强types语言的威胁。
由于C#是微软的产品,而匈牙利的符号是微软的发明,所以我可以看到C#可能会受到影响。
命名一个接口应该有更深远的含义,而不仅仅是把“I”放在名字的前面。
作为一个接口,“水果”和“IFruit”都不会对我有很大的意义。 这是因为它看起来更像一个class级。 类定义的东西,而接口应该定义function。
“I”命名约定有助于区分类和接口,以便开发更容易一些。 虽然不是必需的,但它肯定有助于避免常见的面向对象的编码问题。 和Java一样,C#只允许从一个基类inheritance。 但是,您可以根据需要实现尽可能多的接口。 需要注意的是,如果您从一个类inheritance并实现一个或多个接口,则必须首先命名基类(即,类Trout:Fish,ISwimmer,IDiver …)。
我真的很喜欢根据它们提供的function以及它们是什么types的接口(即animation或无生命的接口)来命名我的接口。
如果您专注于界面提供的function,您可以快速确定界面的名称。 它也可以帮助您快速查看您的界面是否定义了无关的function。
定义无生命对象的接口(即不能自己动作的东西)…我喜欢用最后的IPrintable(如Document,Invoice)IPlayable(比如Instrument,MediaPlayer) (如Document,Image)IEdible(如Fruit,Beef)可以存取(如Car)IFlyable(如Plane)
定义animation对象的接口(也就是自己动作的东西)…我喜欢用…来命名它们……呃,最后是ISwimer(比如鱼,鸭,鸭)IDiver(比如鱼,鸭)IFlyer如Pilot)IDriver(如NascarDriver)
最后,“I”命名约定有助于区分接口和类。 但是,除了开头的“I”之外,还可以添加额外的命名逻辑。
事实是,每个人都明白这一点,而编写更好的代码的一部分使得阅读和理解变得容易。
我不太喜欢这个惯例。 我明白,当你有一个接口和一个具有相同名称的实现时,它会帮助你,但是我觉得它很难看。 当然,如果这是我工作的惯例,我仍然会遵守。 一致性是约定的重点,一致性是一件非常好的事情。
我喜欢用一个接口描述接口以尽可能通用的方式进行的操作,例如Validator
。 validation特定事物的特定实现将是一个ThingValidator
,并且具有由Validator
共享的一些抽象function的实现将是AbstractValidator
。 即使Thing
是唯一的…嗯…我正在validation的事情,而且Validator
将是通用的。
在只有一个具体类对于接口有意义的情况下,我仍然试图描述特定的具体实现,而不是以不同的方式命名接口来防止名称冲突。 毕竟,我将比实现的名称更频繁地input接口的名称。
您可以将“接口”一词作为后缀添加到您的自定义接口中,例如“SerializerInterface”。 对于抽象类,“水果”,比如“FruitAbstract”,或者你可以把它做成“AbstractFruit”,一切都是一致的。 这是足够可读的,或遵循通常的命名约定。
只是我2美分:
我个人追加后缀“Interface”的原因是因为比“I”前缀更容易阅读,而且系统中的文件被列为“分组”。 例如:
不太好:
Alien.php Host.php IAlien.php IHost.php IXenomorph.php Xenomorph.php
更好:
Alien.php AlienInterface.php Host.php HostInterface.php Xenomorph.php XenomorphInterface.php
但这只是个人的品味。 我认为,只要在整个项目中使用一致的命名约定,没有任何说法反对使用自己的命名约定。