答案 0 :(得分:53)
完全相反,命名约定清楚地标识了一个接口。
例如,如果你有:
public class Dog : IPet, IMammal
{
....
仅仅是阅读它,我可以放心地假设IPet和IMammal可能是接口。
.NET CLR允许单类继承。所以,如果我有一个基类..我只能从它继承一个类。让我们将IPet接口更改为基类。我们的示例现在变为
public class Dog : Pet, IMammal
{
....
我从Pet类继承并实现了IMammal接口。
如果我们按照你的建议去做并删除了字母“我”,我们就有了这个:
public class Dog : Pet, Mammal
{
....
我继承的是哪一堂课?我正在实施哪个界面?这让人感到困惑吧? (仅供参考。你应该把基类放在第一位,所以你可以争论这一点......但是如果你想从界面名称前面删除字母I,我怀疑你也遵循这种做法)
正如您所看到的那样,命名约定很容易让我对我的对象有很多了解,而我无需进一步调查。我可以很容易地看到我继承的内容与我正在实施的内容。
答案 1 :(得分:30)
我也喜欢它,因为我可以将它读作“我动词行为”,如“ICanSave”或“IDoDoubleEntry”等......
答案 2 :(得分:24)
我认为IInterface命名约定很愚蠢。这是匈牙利符号的一个例子,我赞同鄙视匈牙利符号的思想学派。如果您的接口只有一个具有相同名称的实现,请考虑这可能是代码异味。
但是,我仍然使用它,因为在这种情况下,Microsoft推荐使用IInterface,并且“标准优于更好”。
答案 3 :(得分:13)
为什么这不是语法高亮而不是匈牙利符号的功能?如果区分类和接口如此重要,那么为什么IDE不会仅仅使用引用接口的标识符。我讨厌在字段之前放置“”或“m ”,在课程之前放置“C”等等。更糟糕的是,它鼓励程序员编写非常糟糕的API,例如:
public class List : IList
而不是更合理:
public class LinkedList : List
public class ArrayList : List
public class HashList : List
甚至.NET公共类作者都陷入了这个陷阱。类名永远不应该是只删除了“I”的接口的名称。类名应始终告诉用户类与接口的其他可能实现的不同之处。因为这个原因我投票放弃了愚蠢的“我”。
另外,当我使用intellisense时,我想按功能区域分组,而不是它是一个类还是接口。我从不认为,“我需要一个界面,而不是一个类。”我一直认为,“我需要能做X的事情。”
答案 4 :(得分:11)
实际上我发现避免命名冲突很有用,例如我可以创建一个名为Fred的具体类来实现IFred
答案 5 :(得分:4)
如果你考虑两个"最佳实践 - 格言"
清晰度为王
和
噪音不好
这些之间存在冲突。问题是:什么时候清晰度会变成噪音?
对我而言,写Person person = new PersonImpl()
比IPerson person = new Person()
更嘈杂(但同样清晰)。
答案 6 :(得分:4)
我一直认为将动词用于行为界面很有趣。这与使用名词的类命名约定不同,但它允许类“说出”它的行为。
class Dog: IBark
这对于像WCF接口这样的结构接口效果不佳,但我们不需要一直玩得开心。
回答你的问题,将I
视为“实现”所以......
class DogDataService : Dog, IDataService
此服务类继承自Dog
并实现IDataService
我仍然没有真正回答你的问题,但是I
很有用,因为你得到命名空间,类和接口之间的命名冲突。
namespace DataService
interface DataService
class DataService: DataService
所以我们最终得到了
namespace DataServices
interface IDataService
class DataService : IDataService
我认为实际上,这是一种理智的惯例。
答案 7 :(得分:3)
或者将“Impl”添加到接口的实现中(argh)。我对“I”没有问题,它是界面最简单,最直接的命名。
答案 8 :(得分:3)
“我”惯例似乎是一个旧的惯例,今天不相关。当前的代码编辑器提供了许多关于您正在使用的类型的见解,因此认为识别接口更容易就像要求命名空间以“N”为前缀,因为您要确保不会将其与具体的类(带有“C”的前缀?)。
约定并不意味着这是一个很好的约定。有时,这只是因为人们开始使用它......
以C#文档生成器为例:它并不关心它...如果你的界面没有以“我”作为前缀,你仍然会在文档的界面部分看到你的界面。您是否真的认为在文档的界面部分中为所有接口添加前缀“I”是相关信息并帮助您更好地识别接口?
答案 9 :(得分:2)
区分界面和类的需要实际上表明了设计缺陷。在设计良好的应用程序中,它总是很清楚。子类应该始终是一个专门化,类只能专注于一个主题,而不是更多。
一个班级应该有一个存在的理由。永远不需要将辅助角色放在基类中。 E.g:
public class XmlConfigurationFile : ConfigurationFile, IDisposable
{
}
public class YamlConfigurationFile : ConfigurationFile, IDisposable
{
}
第一个是专门用于Xml的配置文件,第二个是专门用于Yaml的配置文件。这些也是一次性的,但这并不重要。由于处理过程不同,您没有创建这两个类。
用以下方法对此进行评价:
public class XmlConfigurationFile : IDisposable, ConfigurationFile
{
}
这将告诉您XmlConfigurationFile的主要用途是它是一次性的。您可以将它用作表示配置文件的一种方法很好,但它是次要的。
当您创建具有多个存在理由的类时,问题就开始了:
public class MyConfigurationFile : XmlConfigurationFile, YamlConfigurationFile
{
}
即使XmlConfigurationFile和YamlConfigurationFile是接口,它仍然表明设计不好。你的配置文件如何同时是Xml和Yaml?
如果你仔细阅读给出的例子(这里和其他地方),人们总是很难找到I前缀何时重要的好例子。其中一个答案是:
public class Dog : Pet, Mammal
{
}
这就是这个类在关于宠物的应用程序中的样子。狗的主要目的是成为一种专门的宠物,可以做与宠物有关的事情,而不是哺乳动物。
public class Dog : Mammal, Pet
{
}
这是关于动物分类的应用程序中相同类的外观。很高兴知道狗是宠物,但它的主要目的是成为一种专门的哺乳动物,可以做与哺乳动物有关的事情。
我认为您的课程应该告诉您有关应用程序的体系结构和域的正确故事。要求界面以“I”为前缀是技术要求,并不能帮助您更好地讲述应用程序的故事。
一旦你开始编写小型的,专用的,单一用途的类,知道它是否实现或扩展的需要将自动消失。
答案 10 :(得分:2)
它使其易于识别为界面。
答案 11 :(得分:1)
命名约定提供了在使用之前告诉您有关该对象的一些好处。命名约定已被广泛使用多年,一直回到fortran的坚持,即整数值被限制(如果我没记错的话)变量名称如“i”和“j”。
Hungariation表示法将命名约定带到了一个全新的丑陋程度,描述了变量类型,无论它是否是指针等等。我们中许多人用匈牙利符号暴露了大量代码,发生了紧张的抽搐和口头口吃。
使用I前缀接口名称是一种识别该对象的影响相对较小,无害的方法。
答案 12 :(得分:1)
TL; DR - 从interface IFoo
中提取class Foo
在SOLID解耦中很常见,特别是对于单元测试目的
对我来说,实现接口Foo
的类IFoo
的双重约定(特别是如果两者都在同一个程序集中)传达了一个特定的意图:
Foo
的依赖关系应始终是间接的,通过相应的IFoo
接口(并且可能通过IoC容器注入)IFoo
的初始设计是专有的,不可重用的接口,专门用于允许依赖于Foo
的类在单元测试期间模拟这种依赖性。IFoo
界面的设计中推断任何其他智能IFoo
的具体实现类,则需要将适当的接口隔离设计改装到层次结构中。<强>原理强>
为了能够模拟或者确定一个类,单元测试中广泛接受的最佳实践是仅通过接口来解耦类之间的依赖关系。这个接口也将被解耦到否则会never had a design requirement for polymorphicism的类(即只有一个这样的实现存在,如果它不需要单元测试)。
因此,这些接口的重构和重用(例如Interface Segregation Principal of SOLID
)并不经常应用于这种“可模拟”接口 - 公共方法,属性和属性之间通常存在1:1的相关性。 “可模拟”类(Foo
)及其解耦接口IFoo
的事件(类似于COM时代automatic interfaces in VB)。
VS和Resharper等工具可以将这样的公共符号从类中提取到一个单独的界面中,作为事后的想法。
此外,如果我们认为像Moq这样的Mocking框架允许definition of implementations of the interface on-the-fly,我们就不必浪费时间来命名具体的测试双实现类。
答案 13 :(得分:0)
首先,我认为前缀为I然后描述是错误的,因为它意味着实现可以有一个更短的名称。 IList(intf) - &gt;名单。这是一个反模式,因为我们都知道我们应该在创建时使用intf并且可能只是具体类型。不要焚烧我这是一个概括,但前提是intf很少impl。实现名称应该描述它是如何实现intf或它正在做什么的。想想使用链表实现List的List,LinkedList。谁在乎它是否更长,因为我们应该在大多数时间使用List。如果我们有一个实现了许多intf的类,我们可能不应该将所有intf作为阴影包含在类的真正目的中。在没有intf的情况下移除的东西是有道理的。例如,ppl通过名字给我打电话,而不是使用我的名字的人,兄弟,开发人员等是最具描述性的名称。我想如果一个类是impl一个简单的intf然后调用它的默认Intf,这使它成为ious这是Intf的默认实现。 类的名称最终应该是人类可读的,几乎是描述其目的的短语。前缀代码等不是很好,因为我们与单词和代码进行通信。计算机确实可以调用哪些类,所以为什么我们会命名,所以这些名称可以帮助我们和我们的同事。
答案 14 :(得分:0)
这只是一个命名约定,所以每个人都知道它是一个接口还是别的东西它不是强制性的,也不是编译器或IDE,但是我一生中看到的所有接口都以字母I开头/ p>
答案 15 :(得分:0)
我似乎是匈牙利表示法的传统惯例。 Interface Naming Guidelines说&#34;用字母I前缀接口名称,表示该类型是接口。&#34; Framework Design Guidelines也说&#34; DO前缀接口名称和字母I,表示该类型是接口。&#34;
这只是一种编码惯例,因此很难确定好坏。 重要的是一致性。
答案 16 :(得分:-1)
有了关于命名约定的所有参数,并给实际描述它们所做的变量和方法的专有名称...为什么不只是命名你的接口(例如PetInterface,PlayerInterface等)并取消前缀“我“全都在一起。所以你必须输入另外9个字母,至少删除“I”,我们知道它不是一个类,因为它说“接口”。
答案 17 :(得分:-1)
最有可能的是它可以在intellisense中轻松识别,因为所有接口都会聚集在一起。类似于我使用btn,tb,lb为我的所有UI控件添加前缀。当intellisense踢出所有内容时,在一个简单的组中聚集在一起。