Java接口命名

大多数面向对象语言的接口名称都以大写的I开头,为什么Java不这样做呢?不遵循这一惯例的理由是什么?

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

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

在大多数语言中:

类=用户,接口= IUser

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

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

240741 次浏览

这两者真的有区别吗:

class User implements IUser

而且

class UserImpl implements User

如果我们讨论的是命名惯例?

就我个人而言,我不喜欢在接口前面使用I,因为我想对接口进行编码,并且我认为在命名约定方面更重要。如果调用接口IUser,则该类的每个消费者都需要知道它是IUser。如果你调用类UserImpl,那么只有类和DI容器知道Impl部分,而消费者只知道他们正在使用User

然后,我被迫使用Impl的时间,因为一个更好的名字没有出现自己已经很少,因为实现被命名为根据的实现,因为这是它的重要之处,例如。

class DbBasedAccountDAO implements AccountDAO
class InMemoryAccountDAO implements AccountDAO

根据我的经验,“I”约定适用于旨在向类提供契约的接口,特别是当接口本身不是类的抽象概念时。

例如,在你的情况下,我只希望看到IUser,如果你想拥有的唯一用户是User。如果你计划有不同类型的用户——NoviceUserExpertUser,等等——我希望看到一个User接口(还有,也许,一个实现一些常见功能的AbstractUser类,比如get/setName())。

我还希望定义功能的接口——ComparableIterable等——这样命名,而不是像IComparableIIterable那样命名。

还有另一种约定,被包括Spring在内的许多开源项目所使用。

interface User {
}


class DefaultUser implements User {
}


class AnotherClassOfUser implements User {
}

我个人不喜欢“I”前缀,原因很简单,它是一个可选的约定。所以,如果我采用这种IOPConnection意味着接口的IOPConnection?如果类没有“I”前缀,那么我是否知道它不是一个接口呢?这里的答案是否定的,因为约定并不总是遵循的,监管它们将创建更多的工作,而约定本身节省了。

Java通常不使用IUser约定可能有几个原因。

  1. 面向对象方法的一部分是,您不应该知道客户机使用的是接口还是实现类。所以,即使List是一个接口而String是一个实际的类,一个方法也可能同时被传递——从视觉上区分接口是没有意义的。

  2. 一般来说,我们实际上更喜欢在客户端代码中使用接口(例如,更喜欢List而不是ArrayList)。因此,将接口作为例外突出是没有意义的。

  3. Java命名约定更喜欢具有实际含义的较长的名称,而不是匈牙利风格的前缀。因此,代码将尽可能具有可读性:List表示列表,User表示用户——而不是IUser。

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

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

所以,你从一个实现开始,即没有接口。 稍后你决定,这里需要一个接口,所以你将你的类转换为一个接口

那么很明显:你原来的类叫User。你的界面现在被称为User。也许你有一个UserProdImpl和一个UserTestImpl。如果你的应用程序设计得很好,每个类(除了实例化User的类)都不会改变,不会注意到它们突然被传递了一个接口。

接口用户实现UserImpl。

我不喜欢在接口上使用前缀:

  • 前缀损害了可读性。

  • 在客户端中使用接口是编程的标准最佳方式,因此接口名称应该尽可能简短而美观。实现类应该更加丑陋,以阻止它们的使用。

  • 当从抽象类更改为接口时,前缀为I的编码惯例意味着重命名类的所有出现项——这不好!

在c#中是这样的

public class AdminForumUser : UserBase, IUser

Java会说

public class AdminForumUser extends User implements ForumUserInterface

正因为如此,我认为在java中,约定对于接口来说并没有那么重要,因为继承和接口实现之间有明显的区别。我会说选择任何你喜欢的命名约定,只要你是一致的,并使用一些东西向人们展示这些是接口。我已经好几年没有使用java了,但是所有的接口都在它们自己的目录下,这是惯例。从来没有什么问题。

这是真正意义上更广泛的命名惯例吗?我更倾向于c++,而不是Java及其后代。有多少语言社区使用I约定?

如果这里有独立于语言的商店标准命名约定,请使用它。如果不是,请遵循语言命名约定。

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

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

比这个:

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

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

唯一应该关心实际具体类的代码是具体类的构造位置。其他所有内容都应该使用接口编写。

如果您这样做了,那么像“UserImpl”这样“难看”的具体类名应该安全地隐藏在代码的其余部分中,这些代码可以愉快地继续使用“漂亮”的接口名。

正如另一位发帖者所说,通常更可取的做法是让接口定义功能,而不是类型。我倾向于不“实现”像“User”这样的东西,这就是为什么在这里描述的方式中“IUser”通常不是真正必要的。我经常把类看作名词,把接口看作形容词:

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

有时形容词没有意义,但我仍然通常使用接口来建模行为、动作、功能、属性等等……没有类型。

另外,如果你只创建一个User,并将其命名为User,那么还有IUser接口的意义何在?如果您将有几个不同类型的用户需要实现一个公共接口,那么在选择实现名称时,在接口上附加一个“I”会为您节省什么呢?

我认为一个更现实的例子是,某些类型的用户需要能够登录到特定的API。我们可以定义一个Login接口,然后有一个带有SuperUser、DefaultUser、AdminUser、AdministrativeContact等子类的“User”父类,其中一些会或不会在必要时实现Login(可登录的?)接口。

在Wicket框架中也使用了“I”前缀,我很快就习惯了它。一般来说,我欢迎任何缩短笨重Java类名的约定。但是,在目录和Javadoc中,所有东西都按字母顺序排列在“I”下面,这很麻烦。

Wicket的编码实践类似于Swing,因为许多控件/小部件实例被构造为带有内联方法声明的匿名内部类。令人恼火的是,它与Swing有180度的不同,Swing为实现类使用前缀(“J”)。

“Impl”后缀是一个蹩脚的缩写,不能很好地国际化。如果我们至少用“小恶魔”的话,它会更可爱(也更短)。“Impl”用于IOC,特别是Spring,所以我们现在有点被它困住了。不过,在一个代码库的三个不同部分遵循三种不同的约定有点分裂。