大多数OO语言都用一个资本i来前缀他们的接口名称,为什么Java不这么做呢?不遵守本公约的理由是什么?
为了证明我的意思,如果我想拥有一个用户界面和一个用户实现,我将在Java中有两个选择:
Class = User, Interface = UserInterface
Class = UserImpl, Interface = User
在大多数语言中:
Class = User, Interface = IUser
现在,您可能会争辩说,您总是可以为用户实现选择一个最具描述性的名称,问题就消失了,但是Java推动Pojo方法来处理事情和大多数IOC容器都使用动态代理。这两件事结合在一起意味着您将拥有许多具有单个POJO实现的接口。
所以,我想我的问题归结为:"是否值得遵循更广泛的接口命名约定,特别是考虑到Java框架的方向?"
- "大多数语言在哪里?"除了.NET之外还有哪些语言?
- 也不是所有的.NET;C++是一个可用的.NET语言,并且本身没有接口(抽象基类可以附带一些实现)。这个问题归结为"为什么Java不像C?"?
- 不,问题是基于Java的,但它实际上是一个关于接口命名约定的问题,以及为什么有些语言选择以某种方式来做事情。
- 不同的语言社区有不同的命名约定,这在很长一段时间内都是如此。了解命名规则的起源有时本质上是民俗研究。
- Eclipse是一个重要的异常点,它使用Java与IFOO样式命名。wiki.eclipse.org/naming_惯例
- 除了.NET之外,Adobe Flash/Flex还使用ifoo命名约定。
- 在.NET接口之前,通常使用i前缀命名COM接口,例如iunknown、istream。在C++中,当连接到COM时,通常使用ISTRAM*等。虽然.NET放弃了类前缀这一点很有趣,但它似乎是类的C前缀的自然扩展。Delphi对自己的接口以及对COM接口的使用都使用了相同的约定。就我个人而言,我不介意会议。这里的OP问题表示了一些对Java接口命名约定的失望,我希望已经设置了一个标准。
- 如果您查看Android SDK(Java)中的接口名称,您将看到它们使用接口名称结束时具有Word接口的约定,如EDCOX1×0,EDCOX1,1,等等。
- 当这个问题如此受欢迎,那么多人都感兴趣时,怎么能把它"封闭而不是建设性的"?
- 因为它没有正确的答案。我以前问过,所以对它接受的各种问题都很严格。
- 我尊重你,你自己,发现问题被解决的价值。然而,如果它是措辞的话,这实际上是一个可以回答的问题。此外,即使它是关闭的,它也可以被用来标记其他(可能更好的措辞)非关闭的问题作为副本。这是不合理的。基于Java库,如果它们遵循它们自己的约定,它将是接口[YouTrimeNeNeM];基于EDCOX1(2)。
- 迄今为止,关于类和接口的命名约定,我发现的最好建议是:"接口名应该总是一个形容词(尽可能)来描述类(名词)的强制行为!"如前所述-iwombat.com/standards/…
- 我使用这里介绍的惯例。howtoonijava.com/java/basics/java-naming-conventions
我不喜欢在接口上使用前缀:
- 完全同意。如果使用自动完成功能,还需要键入一个键。很多文件都是以i开头的。
- 任何一个合适的IDE都可以让您轻松地更改代码。另外,当从抽象类更改为接口时,我很确定您的客户机无论如何都需要重新编译。
- 非常晚了,但是:如果一个IDE使更改某个东西的名称变得容易,那就一点也不重要了。使用某个类型的实例的代码永远不应该关心该类型是接口、类还是什么。因此,以类型的名义公开这样的细节是没有意义的,并且对理解有害。它所公开的类型和合同才是最重要的!
- @AllainLalond只有当你同时拥有界面和你控制的所有客户机时,这才是真的,通常情况并非如此。
- 此外,如果您要使用ifoo的方法,那么它不应该是实现的cfoo吗?当然,如果失败了,方法会抛出一个efoo。
- "前缀损害可读性"纯粹是主观的。和大多数命名约定一样。更重要的是,您的团队就如何做达成一致,从而使代码库保持一致。
- "…抽象类到接口…prefix i意味着重命名类中所有出现的内容"—这有什么坏处?除了工具使重命名变得简单之外,将某个抽象类更改为接口也是一个重要的更改(如果没有其他更改,则是从"implements"更改为"extends")。
- @阿拉林隆德仍然在手术期间,你将不得不提交一份可能导致混乱的文件。巨额承诺本身就是一件坏事。
- @allainllonde,一些字节码操作工具需要字符串形式的类型的完整限定名才能在类路径中找到它。考虑用一个IDE重命名所有这些引用。
- 我个人喜欢C对IInterface和OtherTypes的处理方法(老实说,如果有一个合适的信号,也会很好)。我发现这种一致性总体上有助于提高可读性。从一个类型转换为一个接口,反之亦然,Java和C语言中的源代码都会发生变化,这完全否定了"重命名事件"的观点。一个好的IDE(如Resharper)可以帮助您通过源代码库安全而琐碎地进行更改。
- eclipse:"对于接口名称,我们遵循接口约定的"i":所有接口名称都以"i"作为前缀。例如,"iWorkSpace"或"iIndex"。这种约定通过使接口名称更容易识别来帮助代码的可读性。"
- "前缀损害可读性。"那么string.xml中的名称呢?就像str ou close,str ou ok…
- @这是一个重言式,就像I前缀一样,是无用的重复信息。public interface XXX告诉你这是Interface。与匈牙利符号相同,现代语言不需要这种符号,因为现代语言不再是C,甚至不再是C,它有一个体面的ide,当你悬停在一个变量上时可以告诉你类型。
- 匈牙利符号也使得在IDE中完成名称变得更加困难。在名字开始之前,你必须记住前缀的类型和类型,我觉得这很麻烦。
- 在wiki.eclipse.org/naming_conventions中,对于接口名称,我们遵循"i"-对于接口约定:所有接口名称都以"i"作为前缀。例如,"iWorkSpace"或"iIndex"。这种约定通过使接口名称更容易识别来帮助代码的可读性。"
以下两者之间是否真的存在差异:
1
| class User implements IUser |
和
1
| class UserImpl implements User |
如果我们所说的只是命名约定?
就我个人而言,我不喜欢在与I的接口之前,因为我想对接口进行编码,我认为这在命名约定方面更重要。如果调用接口IUser,那么该类的每个使用者都需要知道它的IUser。如果您调用类UserImpl,那么只有类和您的DI容器知道Impl部分,并且消费者只知道他们正在使用User。
另外,由于没有更好的名称,我被迫使用Impl的次数非常少,因为实现是根据实现来命名的,因为这是很重要的,例如。
1 2
| class DbBasedAccountDAO implements AccountDAO
class InMemoryAccountDAO implements AccountDAO |
- 我想您应该知道它是一个DAO,因为它描述了一般的功能,而不需要打开类。如果我在项目中查看类文件,那么通过查找*dao可以很容易地看到所有的dao
- DAO是数据库访问的一个众所周知的模式,因此名称中包含该模式可以很容易地通过查看它的名称来了解类的作用。另外,最好严格遵循camel符号("accountdao"),比如mina.apache.org/changes-between-2X-and-1X.html。
- @标记,它不像有一个I来表示一个接口。DAO告诉您类或接口是用于访问帐户数据的对象,而这正是对象所做的。我告诉你它是一个接口,它与对象本身无关,只与语言的语义有关。
- 当你展示它时,它的前缀和后缀。
- @安德烈:不,这是语义("dao")与语言工件的不必要修饰("i"如在接口中;这是一个事实,无论如何在代码中都提到了"interface ifoo…")
- 有趣的阅读:接口和类命名反模式。
- 那不是我刚才说的吗?
- 在这个特定的示例中,我看不到将实现与接口分离的任何理由。userimpl没有具体说明用户是如何实现的。实现的名称应该使其具体化。
可能有几个原因Java一般不使用IUSER约定。
面向对象方法的一部分是,您不必知道客户机是使用接口还是实现类。所以,即使列表是一个接口,字符串也是一个实际的类,一个方法可能同时被传递给这两个类——从视觉上区分接口是没有意义的。
一般来说,我们更喜欢在客户机代码中使用接口(例如,更喜欢列表而不是arraylist)。因此,让接口作为异常突出是没有意义的。
Java命名约定更喜欢具有匈牙利风格前缀的实际名称。这样代码将尽可能可读:一个列表代表一个列表,一个用户代表一个用户,而不是一个iuser。
还有另一个约定,被包括Spring在内的许多开源项目使用。
1 2 3 4 5 6 7 8
| interface User {
}
class DefaultUser implements User {
}
class AnotherClassOfUser implements User {
} |
我个人不喜欢"i"前缀,原因很简单,它是一个可选的约定。所以如果我采用这一点,IIopConnection是否意味着IOPConnection的接口?如果类没有"i"前缀,那么我是否知道它不是一个接口……这里的答案是"否",因为并不总是遵循约定,并且对它们进行管理将创建约定本身保存的更多工作。
- 我喜欢这一点,因为它也有助于使您进入将接口用于外部依赖的模式,而不是耦合类。
正如另一个海报所说,通常情况下,最好让接口定义功能,而不是类型。我倾向于不"实现"类似"用户"的东西,这就是为什么"i user"在这里描述的方式中通常不是真正必要的。我经常把类看作名词,把接口看作形容词:
有时形容词没有意义,但我仍然通常使用接口来建模行为、动作、能力、属性等。不是类型。
另外,如果你真的只想让一个用户称之为用户,那么拥有一个iuser接口又有什么意义呢?如果您有几个不同类型的用户需要实现一个公共接口,那么在接口上附加一个"i"会使您在选择实现的名称时节省什么呢?
我认为一个更现实的例子是,某些类型的用户需要能够登录到特定的API。我们可以定义一个登录界面,然后用superuser、defaultuser、adminuser、administrativecontact等类创建一个"用户"父类,其中一些类将实现或不实现登录(loginable?)必要时提供接口。
- 我认为你提供的支持"接口作为形容词"的例子是有偏差的,因为这些接口更像混合输入(或特性)。因此,介面对形容词和名词都很好,但可能对indefinite transitive verbs8^p不好。
- 这在过去几年可能会改变。Oracle文档。允许接口为类型:[Link ] DOCS.Oracle .COM/JavaSe/Tudio/Java/IandI /IdFraseType .H‌
鲍勃李在一次演讲中说:
whats the point of an interface if you
have only one implementation.
因此,您从一个实现开始,即没有接口。稍后您决定,这里需要一个接口,所以您可以将类转换为接口。
然后很明显:您的原始类被称为用户。您的界面现在称为用户。也许你有一个userprodimpl和一个usertestimpl。如果您的应用程序设计得很好,那么每个类(实例化用户的类除外)都将保持不变,并且不会注意到它们突然通过了一个接口。
这样就清楚了->界面用户实现userimpl。
- 使用接口有助于测试驱动的开发。我们在域外模型和测试中遇到了许多问题,因为我们决定不使用接口。我的一个朋友曾经引用过这样的话:"一切都是一个界面,从长远来看,它会拯救你。"
- 如果您使用easymock,那么对于一个额外的接口没有真正的用途。如果您不使用像em这样的东西,是的,那么对于需要测试的类中作为依赖项的每个类,都需要一个接口。->所以您将有多个IMPL(test+real)
- 模拟和简单的代理支持。我相信提供接口还有其他原因。
- 正如我最近对一位同事所说,现在介绍一个界面并不需要花费什么,但可以在以后为您节省大量时间。
- 如果您在不久的将来有其他实现,那么一个接口将是一个优势。
- 如果您在不久的将来有其他实现,那么一个接口将是一个优势。拥有这个接口可以清楚地说明契约,而在已经实现的情况下,您可以很容易地忽略一个您可能不希望出现的公共方法。同样,尽管这不应该是决定性的原因,但是使用接口有助于将任务分成多个开发人员的团队。例如,当您执行某个类的实现时,有人正在使用该实现来处理该类。
- 我很好奇TDD的命名约定在只有一个(生产)实现的接口的情况下使用了什么;我想知道,值得一提的是,TDD本身……?
- 告诉我类型是一个接口,违反了我作为客户机不知道或不关心它是什么的权利。如果我需要一个foo,给我一个foo。我会和foo谈谈,但不要让我记住foo是什么。我不知道。我不想知道。所以不要给我一次机会来迷惑我。
- 我不喜欢"我将来可能需要另一个IMPL"的论点。我更喜欢雅格尼的方法:不要为尚未发生的事情做计划。
- 现代的模拟框架不需要接口——它们可以模拟和监视具体的对象。
- 界面应该被战略性地放置在您预期变更的地方。每个接口都是一个权衡,即至少有一个运行时调度开销指针没有编译时依赖性。在大多数情况下,它们是不必要的,但是如果你不把它们放在你预期的变化的地方,你可以很容易地把你的程序放在一个需要完全重写以满足新需求的状态(由于严重耦合到不需要的非接口依赖,共同的罪魁祸首是框架和IO通道(如数据库))。
- 只有一个实现有数百万的理由。只有一个词足以描述它们:抽象
在C中,它是
1
| public class AdminForumUser : UserBase, IUser |
Java会说
1
| public class AdminForumUser extends User implements ForumUserInterface |
因此,在继承接口和接口实现之间存在明显的差异,我认为在Java中,约定对于接口几乎不重要。我想说的是,只要您是一致的,并且使用一些东西向人们展示这些是接口,就可以选择您想要的任何命名约定。在几年内还没有做过Java,但是所有的接口都在自己的目录中,这就是惯例。从来没有真正的问题。
- 也许我是个蹩脚的Java程序员,但我更喜欢C语言风格,意思是所有的接口都是以"我的前缀"开头的。
- 我不知道你和其他人是从哪里得到这个约定的。这在Java库中是不明显的…
根据我的经验,"i"约定适用于旨在向类提供契约的接口,特别是当接口本身不是类的抽象概念时。
例如,在您的情况下,我只希望看到IUser,如果您唯一想要的用户是User。如果您计划有不同类型的用户-NoviceUser、ExpertUser等-我希望看到一个User接口(可能还有一个AbstractUser类,它实现一些公共功能,如get/setName())。
我还希望定义功能的接口——Comparable、Iterable等——可以这样命名,而不像IComparable或IIterable。
- 如果你想拥有的唯一用户是用户,为什么不直接使用用户而不是界面呢?
- 在一些客户机/服务器架构中,客户机端需要知道接口,而不需要重量级的服务器实现。
遵循良好的OO原则,您的代码应该(尽可能)依赖于抽象,而不是具体的类。例如,编写这样的方法通常更好:
1 2 3
| public void doSomething (Collection someStuff ) {
...
} |
比这个:
1 2 3
| public void doSomething (Vector someStuff ) {
...
} |
如果您遵循这个想法,那么我坚持认为,如果您给接口命名如"用户"和"银行帐户"(例如),而不是"i user"、"用户界面"或其他变体,您的代码将更易于阅读。
唯一应该关心实际具体类的代码位是构建具体类的地方。其他一切都应该使用接口编写。
如果这样做,那么"丑陋的"具体类名(如"userimpl")应该被安全地隐藏在代码的其余部分,这样可以愉快地继续使用"nice"接口名。
- 但是,当您只需要一个或两个接口时,为什么还要为程序中的每个类创建匹配的接口呢?
=v=wicket框架中也使用了"i"前缀,我很快就习惯了。一般来说,我欢迎任何缩短繁琐Java类名称的约定。不过,在目录和javadoc中,所有东西都按字母顺序排列在"i"下,这是一个难题。
Wicket编码实践类似于Swing,因为许多控件/小部件实例被构造为带有内联方法声明的匿名内部类。令人恼火的是,它与Swing的180度不同之处在于Swing对实现类使用了前缀("j")。
"impl"后缀是一个冗长的缩写,不能很好地国际化。如果我们至少和"小鬼"一起走,那就更可爱(更短)。IMPL"用于IOC,尤其是Spring,所以我们现在有点纠结于此。不过,它在一个代码库的三个不同部分中遵循3种不同的约定,会有点分裂。
这是一个更广泛的命名约定吗?我更多的是C++方面,而不是真正的Java和后代。有多少语言社区使用i约定?
如果您在这里有一个独立于语言的商店标准命名约定,请使用它。如果没有,请使用语言命名约定。