Java接口命名[关闭]


324

大多数OO语言的接口名称都以大写的I开头,为什么Java不这样做呢?不遵守该公约的理由是什么?

为了说明我的意思,如果我想拥有一个用户界面和一个用户实现,那么在Java中我有两种选择:

  1. 类=用户,接口= UserInterface
  2. 类= UserImpl,接口=用户

在大多数语言中:

类=用户,接口= IUser

现在,您可能会争辩说,您总是可以为用户实现选择一个最具描述性的名称,问题就消失了,但是Java将POJO方法推向了事物,并且大多数IOC容器广泛使用DynamicProxies。这两件事在一起意味着您将通过单个POJO实现拥有许多接口。

因此,我想我的问题可以归结为:“是否值得遵循更广泛的接口命名约定,尤其是考虑到Java框架的发展方向?”


61
“大多数语言在哪里”?.Net以外的其他语言?
wds

2
不同的语言社区具有不同的命名约定,并且很长一段时间以来都是如此。有时,从本质上讲找出命名惯例的起源是民间文学研究。
David Thornley,2009年

4
Eclipse是使用Java和IFoo样式命名的重要异常值。 wiki.eclipse.org/Naming_Conventions
David Leonard

2
如果你看看在Android SDK中接口的名称(Java的为好),你会看到他们使用具有上的接口名称末尾字接口,像约定NetworkInterfaceDialogInterface
sandalone

21
当这个问题如此受欢迎并且受到很多人的关注时,如何“封闭式地解决问题”?
2014年

Answers:


329

我不想在接口上使用前缀:

  • 前缀会损害可读性。

  • 在客户端中使用接口是最好的标准编程方法,因此接口名称应尽可能简短和令人愉快。实施类应该更丑陋,以阻止其使用。

  • 当从抽象类更改为接口时,带前缀的编码约定意味着重命名该类的所有出现---不好!


12
完全同意。如果您使用自动完成功能,则需要再键入一个键。很多文件以I开头
Kalecser 2009年

85
任何不错的IDE都可以按照您描述的方式轻松更改代码。另外,从抽象类更改为接口时,我很确定您的客户端仍然需要重新编译。
Allain Lalonde

63
超级晚在这里,但:不要紧,在所有如果一个IDE使得改变事物的名称容易。使用某种类型的实例的代码永远不要关心这种类型是接口,类还是其他。因此,以类型名称公开这样的细节是没有意义的,并且不利于理解。它公开的类型和合同很重要!
ColinD 2011年

11
此外,如果您要沿用IFoo的路线,则实现时不应该将它作为CFoo,当然,如果失败,方法会抛出EFoo。
罗宾

57
“前缀会损害可读性”纯粹是主观的。和大多数命名约定一样。您的团队要就如何做达成一致,以使代码库保持一致,这一点更重要。
dreadwail 2012年

121

之间真的有区别吗?

class User implements IUser

class UserImpl implements User

如果我们只讨论命名约定?

就我个人而言,我不希望在接口之前加上,I因为我想对该接口进行编码,并且我认为在命名约定方面更为重要。如果调用该接口,IUser则该类的每个使用者都需要知道其IUser。如果您调用该类,UserImpl则只有该类和您的DI容器知道该Impl零件,而使用者仅知道他们正在使用User

再说一次,Impl由于没有一个更好的名字本身而被迫使用的时间已经很少了,因为实现是根据实现命名的因为这很重要,例如

class DbBasedAccountDAO implements AccountDAO
class InMemoryAccountDAO implements AccountDAO

我认为您想知道它的DAO,因为它描述了常规功能而无需打开类。如果我正在查看项目中的类文件,则通过查找* DAO可以很容易地看到所有DAO
Patrick Patrick

6
DAO是一种众所周知的数据库访问模式,因此在名称中包含该模式可以很容易地通过查看其名称来了解该类的功能。PS最好严格遵循骆驼符号(“ AccountDao”),例如mina.apache.org/changes-between-2x-and-1x.html
Esko Luontola

4
@marker,这不像让I表示接口。DAO告诉您,该类或接口是用于访问帐户数据的对象,而对象正是这样做的。有一个I会告诉您它的接口,该接口与对象本身无关,但与语言的语义无关
tddmonkey

当您介绍它时,其前缀与后缀。
AndreiRînea10年

3
@Andrei:是的,这是语义(“ DAO”)与语言工件的不必要修饰(“ I”,如接口;事实,无论如何在代码中提到“接口IFoo ...”)
Dirk

75

Java通常不使用IUser约定可能有多种原因。

  1. 面向对象方法的一部分是,您不必知道客户端是使用接口还是实现类。因此,即使List是一个接口,而String是一个实际的类,也可能会同时向它们传递一个方法-从视觉上区分这些接口没有意义。

  2. 通常,我们实际上会更喜欢在客户端代码中使用接口(例如,将List首选为ArrayList)。因此,使接口作为例外脱颖而出没有任何意义。

  3. Java命名约定比具有匈牙利含义的前缀更喜欢具有实际含义的较长名称。这样该代码将尽可能地易读:一个List代表一个列表,一个User代表一个用户-而不是IUser。


72

还有一个约定,包括Spring在内的许多开源项目都在使用。

interface User {
}

class DefaultUser implements User {
}

class AnotherClassOfUser implements User {
}

我个人不喜欢“ I”前缀,原因很简单,因为它是可选约定。因此,如果我采用这种方式,那么IIOPConnection是否表示IOPConnection的接口?如果该类没有前缀“ I”,该怎么办呢,我是否知道它不是接口。.答案是否定的,因为并非总是遵循约定,对它们进行监管将产生约定本身保存的更多工作。


我喜欢这一点,因为它还可以帮助您采用将接口用于外部依赖关系的方式,而不是耦合类。
马特·布里格斯

47

正如另一位发布者所说,通常最好让接口定义功能而不是类型。我倾向于不“实现”诸如“ User”之类的东西,这就是为什么“ IUser”通常并不需要此处所述的方式。我经常将类视为名词,将接口视为形容词:

class Number implements Comparable{...}  
class MyThread implements Runnable{...}
class SessionData implements Serializable{....}

有时候,形容词没有任何意义,但我通常还是会使用接口来建模行为,动作,功能,属性等,而不是类型。

另外,如果您真的只打算创建一个User并将其称为User,那么拥有IUser接口又有什么意义呢?而且,如果您需要使用几种不同类型的用户来实现一个通用接口,那么在接口上添加“ I”会为您节省选择实现名称的方式?

我认为一个更现实的例子是某些类型的用户需要能够登录到特定的API。我们可以定义一个Login接口,然后使用SuperUser,DefaultUser,AdminUser,AdministrativeContact等suclass创建一个“ User”父类,其中某些类将根据需要实现或不实现Login(可登录?)接口。


我认为您提供的用于支持“形容词的界面”的示例是歪斜的,因为这些界面的目的更像是混合(或特征)。因此,接口既适合形容词又适合名词-但可能不适用于indefinite transitive verbs 8 ^ P
Stevel

最近几年可能会改变。甲骨文文档。允许将接口作为类型:[link] docs.oracle.com/javase/tutorial/java/IandI/interfaceAsType.html
karlihnos

38

鲍勃·李在一次演讲中说:

如果只有一个实现,接口的意义是什么?

因此,您从一个实现开始,即没有接口。稍后再决定,这里需要一个接口,因此您可以将类转换为接口。

然后它变得显而易见:您的原始类称为User。您的界面现在称为用户。也许您有一个UserProdImpl和一个UserTestImpl。如果您对应用程序进行了精心设计,则每个类(实例化User的类除外)都将保持不变,并且不会注意到它们突然之间通过了接口。

这样就很清楚->界面用户实现UserImpl。


18
使用界面将有助于测试驱动开发。由于我们决定不使用接口,因此在域模型和测试方面遇到了许多问题。我的一个朋友曾经引述过:“一切都是界面,从长远来看,它将为您省钱。”
hooknc 2009年

4
模拟和简单的代理支持。我确信还有其他原因也要提供接口。
MetroidFan2002

3
正如我最近对一位同事所说,现在引入一个界面无需花费任何成本,但是以后可以节省大量时间。
tddmonkey

2
如果您可能在不久的将来有其他实现,那么接口将是一个加号。
Stef

3
我不喜欢“我将来可能需要另一个推动力”的说法。我更喜欢YAGNI的方法:不要为尚未发生的事情做计划。
David Lavender

24

在C#中

public class AdminForumUser : UserBase, IUser

Java会说

public class AdminForumUser extends User implements ForumUserInterface

因此,我认为约定在Java中的接口几乎没有那么重要,因为继承和接口实现之间存在明显的区别。我想说的是,只要您选择一致的名称,就可以选择任何想要的命名约定,并使用某些东西向人们展示这些是接口。几年没做过Java,但是所有接口都只是在它们自己的目录中,这就是约定。从来没有真正有任何问题。


22
也许我不是Java程序员,但是我更喜欢C#风格,这意味着所有接口都以'I'前缀开头:)
davs 2011年

7
我不确定您和其他人从何处获得此约定。在Java库中并不明显...
ChiefTwoPencils 2015年

6

以我的经验,“ I”约定适用于旨在为类提供契约的接口,尤其是当接口本身不是该类的抽象概念时。

例如,就您而言,我只希望查看IUser您打算拥有的唯一用户是否为User。如果您打算拥有不同类型的用户- NoviceUserExpertUser等等-我希望看到一个User接口(也许还有一个AbstractUser实现某些常用功能的类,例如get/setName())。

我还期望定义功能的接口- ComparableIterable等-被命名那样,而不是像IComparableIIterable


如果您打算拥有的唯一用户是User,为什么不使用User而不是界面呢?
卡里汉'17

3
在某些客户端/服务器体系结构中,客户端需要知道接口而无需重量级服务器实现。
David Koelle

5

遵循良好的OO原则,您的代码(在实际/可能的范围内)应依赖于抽象而不是具体的类。例如,通常最好编写这样的方法:

public void doSomething(Collection someStuff) {
    ...
}

比这个:

public void doSomething(Vector someStuff) {
    ...
}

如果您遵循这个想法,那么我坚持认为,如果给接口名称(例如)“ User”和“ BankAccount”(而不是“ IUser”,“ UserInterface”或其他变体),则代码将更具可读性。

唯一需要关注实际具体类的代码是构造具体类的地方。其他所有内容都应使用接口编写。

如果执行此操作,则应从其余代码中安全地隐藏“丑陋”的具体类名称,例如“ UserImpl”,使用“ nice”接口名称可以轻松进行下去。


但是,当只需要一两个东西的接口时,为什么还要为程序中的每个类都创建一个匹配的接口呢?
LegendLength

3

= v = Wicket框架中也使用了“ I”前缀,我很快就习惯了。总的来说,我欢迎任何缩短繁琐的Java类名的约定。但是,麻烦的是,目录和Javadoc中的所有内容都按字母顺序放在“ I”下。

Wicket编码实践与Swing相似,因为许多控件/小部件实例都构造为带有内联方法声明的匿名内部类。令人讨厌的是,它与Swing的区别在于180°,因为Swing为实现类使用前缀(“ J”)。

“ Impl”后缀是一个缩写,并且不能很好地国际化。如果仅让我们至少使用“ Imp”,它将更漂亮(或更短)。“ Impl”用于IOC,尤其是Spring,因此我们暂时还不了解。但是,在一个代码库的三个不同部分中遵循3个不同的约定会有点麻烦。


0

从实际意义上讲,这是更广泛的命名约定吗?我更多地是在C ++方面,而不是真正在Java和后代方面。多少语言社区使用I约定?

如果您在这里有与语言无关的商店标准命名约定,请使用它。如果不是,请遵循语言命名约定。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.