Java中的接口命名

大多数OO语言都是用大写字母I来表示它们的接口名称,为什么Java不这样做呢? 没有遵循这个惯例的理由是什么?

为了演示我的意思,如果我想要一个用户界面和一个用户实现,我会在Java中有两个select:

  1. Class = User,Interface = UserInterface
  2. Class = UserImpl,Interface = User

在大多数语言中:

Class = User,Interface = IUser

现在,你可能会争辩说,你总是可以为用户实现select一个最具描述性的名字,问题就会消失,但是Java将POJO方法推向了事物,大多数IOC容器都广泛地使用了DynamicProxies。 这两件事意味着你将有一个单一的POJO实现的接口。

所以,我想我的问题归结为: “是否值得遵循更广泛的接口命名约定,特别是鉴于Java框架似乎在哪里?

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

  • 前缀会伤害可读性。

  • 在客户端使用接口是编程的标准最佳方式,因此接口名称应尽可能短而宜人。 实施class级应该是丑陋的,以阻止他们的使用。

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

真的有区别:

 class User implements IUser 

 class UserImpl implements User 

如果我们所说的是命名约定?

就我个人而言,我更喜欢不在与“I”的接口之前,因为我想对接口进行编码,我认为在命名约定方面更重要。 如果您调用IUser接口,则该类的每个消费者都需要知道其IUser。 如果您调用UserImpl类,那么只有类和DI容器知道Impl部分,而消费者只知道他们正在与用户一起工作。

再说一次,我被迫使用Impl的时代,因为更好的名字本身并没有出现,因为实现是根据实现来命名的因为这是重要的,例如

 class DbBasedAccountDAO implements AccountDAO class InMemoryAccountDAO implements AccountDAO 

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

  1. 面向对象方法的一部分是,你不应该知道客户端是使用接口还是实现类。 所以,即使List是一个接口,而String是一个实际的类,一个方法可能会被传递给它们两个 – 对于直观地区分接口是没有意义的。

  2. 一般来说,我们实际上更喜欢在客户端代码中使用接口(比如喜欢List到ArrayList)。 因此,使接口脱颖而出是没有意义的。

  3. Java命名约定优先select具有匈牙利式前缀的实际含义的较长名称。 所以代码将尽可能可读:一个List代表一个列表,一个User代表一个用户 – 而不是IUser。

还有另一个约定,许多开源项目(包括Spring)都使用这个约定。

 interface User { } class DefaultUser implements User { } class AnotherClassOfUser implements User { } 

我个人不喜欢“我”前缀的简单原因,它的一个可选的约定。 所以如果我采用这个IIOPConnection意味着IOPConnection的接口? 如果这个类没有“I”前缀,那么我知道它不是一个接口吗?这里的答案是否定的,因为约定并不总是被遵循,并且对它们进行pipe理将会创造更多的约定本身保存的工作。

正如另一张海报所说,通常最好让界面定义不是types的function。 我倾向于不实施像“用户”这样的东西,这就是为什么“IUser”往往不是这样描述的方式真正需要的。 我经常把名词和接口看作是形容词:

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

有时一个形容词没有意义,但我仍然通常使用接口来build模行为,动作,能力,属性等等…不是types。

另外,如果你真的只打算让一个用户称之为用户,那么拥有一个IUser接口又有什么意义呢? 如果你将有一些需要实现一个通用接口的不同types的用户,那么在接口上附加一个“I”会不会让你select实现的名字?

我认为一个更现实的例子是某些types的用户需要能够login到一个特定的API。 我们可以定义一个Login接口,然后有一个带有SuperUser,DefaultUser,AdminUser,AdministrativeContact等等的“User”父类,其中一些将根据需要实现Login(Loginable)接口。

鲍勃李在演讲中曾经说过:

如果你只有一个实现,接口的意义何在。

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

那么很明显:您的原始类被称为“用户”。 你的界面现在被称为用户。 也许你有一个UserProdImpl和一个UserTestImpl。 如果你devise好你的应用程序,每个类(除了实例化User)都将保持不变,并且不会注意到它们突然通过了一个接口。

所以它变得清晰 – >接口用户实现UserImpl。

在C#中是

 public class AdminForumUser : UserBase, IUser 

Java会说

 public class AdminForumUser extends User implements ForumUserInterface 

正因为如此,我不认为约定在接口的java几乎是重要的,因为inheritance和接口实现之间有一个明显的区别。 我会说只要select你想要的任何命名约定,只要你是一致的,并用一些东西来显示这些是接口。 几年之后还没有做过java,但是所有的接口都只是在他们自己的目录中,那就是惯例。 从来没有真正有任何问题。

遵循良好的面向对象的原则,你的代码应该(尽可能地)取决于抽象而不是具体的类。 例如,编写一个像这样的方法通常会更好:

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

比这个:

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

如果你遵循这个想法,那么我认为,如果你给出接口名称,比如“User”和“BankAccount”,而不是“IUser”,“UserInterface”或其他变体,那么你的代码将更具可读性。

应该关心实际具体类的唯一代码是具体类构造的地方。 其他的一切都应该使用接口来编写。

如果你这样做,那么像“UserImpl”这样的“丑陋的”具体类名应该被安全地隐藏起来,而不是其他的代码,它们可以使用“nice”接口名称来快速地继续。

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

例如,在你的情况下,我只希望看到IUser如果你打算有唯一的用户是User 。 如果你打算拥有不同types的用户NoviceUserExpertUser等等 – 我期望看到一个User界面(也许是一个AbstractUser类,它实现了一些常用的function,比如get/setName() )。

我也希望定义能力的接口 – ComparableIterable等 – 可以这样命名,而不是像IComparableIIterable

= v = Wicket框架中也使用了“I”前缀,我已经习惯了它。 一般来说,我欢迎任何缩短繁琐Java类名称的约定。 然而,在目录和Javadoc中,“I”下的所有内容都是按照字母顺序排列的。

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

“Impl”后缀是一个蹩脚的缩写,并没有很好的国际化。 如果只有我们至less用“小鬼”去了,它会是可以(而且更短)。 “Impl”用于国际奥委会,特别是Spring,所以我们现在还在坚持。 虽然在一个代码库的三个不同部分遵循三种不同的约定,但它有点分裂。

这真的是一个更广泛的命名约定吗? 我更多的是C ++方面,而不是真正的Java和后代。 有多less种语言社区使用I惯例?

如果您在这里有独立于语言的商店标准命名惯例,请使用它。 如果没有,请使用语言命名约定。