Java接口/实现命名约定

你如何命名你创build的不同的类/接口? 有时我没有实现信息添加到实现名称 – 如接口FileHandler和类SqlFileHandler

当发生这种情况时,我通常以“普通”名称命名接口,如Truck并命名实际的类TruckClass

你如何在这方面命名接口和类?

命名你的Interface是什么。 Truck 。 不是ITruck因为它不是ITruck ,而是Truck

Java中的Interface是一种types 。 然后你有implement Truck DumpTruckTransferTruckWreckerTruckCementTruck等。

当你使用Interface代替一个子类时,你只需要将它投射到Truck 。 如List<Truck> 。 把I放在前面只是蹩脚的匈牙利风格的符号同义反复 ,只增加了更多的东西来键入你的代码。

所有现代Java IDE的标记接口和实现,还有什么不是没有这个愚蠢的符号。 不要把它TruckClass ,这是重言式,就像IInterface重言式一样糟糕。

如果它是一个实现它是一个类。 这个规则唯一的例外就是AbstractTruck 。 因为只有子类才会看到这一点,所以你不应该投到一个Abstract类,它会添加一些信息,类是抽象的,应该如何使用。 你仍然可以想出一个比AbstractTruck更好的名字,而使用BaseTruck 。 但是由于Abstract类不应该成为任何面向公共的接口的一部分,所以这个规则是可以接受的例外。 要protected施工人员,要跨越这个鸿沟还有很长的路要走。

Impl后缀也是更多的噪音。 更重言式。 任何不是接口的都是一个实现,甚至是部分实现的抽象类。 你打算把这个愚蠢的Impl后缀放在每个Class的每个名字上吗?

Interface是公共方法和属性必须支持的协议,也是types信息。 所有实施Truck是一种Truck

看看Java标准库本身。 你看到IListArrayListImplLinkedListImpl ? 不,您会看到ListArrayList以及LinkedList 。 这是一个关于这个确切问题的好文章 。 任何这些愚蠢的前缀/后缀命名约定都违反了DRY原则。

此外,如果您发现自己将DTOJDOBEAN或其他愚蠢的重复性后缀添加到对象,那么它们可能属于一个包而不是所有这些后缀。 正确打包的命名空间是自我logging,并减less所有这些真正构思不佳的专有命名scheme中的所有无用的冗余信息,大多数地方甚至没有以一致的方式内部遵守。

如果你能想出使你的Class名独特的后缀Impl ,那么你需要重新思考有一个Interface所以,当你有一个Interface和一个单一的Implementation不是唯一专门从Interface你可能不需要Interface

我在这里看到的答案表明,如果你只有一个实现,那么你不需要一个接口。 这是在Depencency Injection / Inversion of Control原理的情况下(不要打电话给我们,我们会打电话给你!)。

所以是的,在某些情况下,您希望简化代码,并通过依靠注入的接口实现(也可以代理 – 您的代码不知道!)使其易于testing。 即使你只有两个实现 – 一个是模拟testing,一个是注入实际的生产代码 – 这不会使界面变得多余。 一个良好的文档界面build立了一个合同,也可以通过严格的模拟实施来维护以进行testing。

事实上,你可以build立一个testing,它可以实现最严格的接口契约(抛出不应该为null的参数的exception等),并在testing中捕获错误,在生产代码中使用更高效的实现(不检查应该例如,由于模拟在您的testing中抛出exception,并且您知道由于在这些testing之后修复代码而引起的参数不为空,所以不能为null。

dependency injection/ IOC对于新手来说可能很难掌握,但是一旦你了解了它的潜力,你就会想要在所有的地方使用它,你会发现自己始终在做接口 – 即使只有一个实际生产)实施。

对于这一个实现(你可以推断,你是对的,我相信testing的模拟应该被称为Mock(InterfaceName)),我更喜欢名称Default(InterfaceName)。 如果更具体的实现出现,可以适当地命名。 这也避免了我特别不喜欢的Impl后缀(如果它不是一个抽象类,那么它就是一个“impl”!)。

我也更喜欢“Base(InterfaceName)”,而不是“Abstract(InterfaceName)”,因为在某些情况下,您希望基类稍后变得可实例化,但是现在您被名为“Abstract(InterfaceName)” ,这迫使你重命名这个类,可能会引起一些小的混淆 – 但是如果它总是Base(InterfaceName),那么移除抽象修饰符不会改变这个类是什么。

接口的名称应该描述接口所代表的抽象概念。 任何实现类都应该有一些特定的特性,可以用来给它一个更具体的名字。

如果只有一个实现类,并且你不能想到任何使它具体化的东西(隐含着想把它命名为-Impl ),那么看起来根本就没有理由拥有一个接口。

我倾向于遵循Java Core / Sunbuild立的伪约定,例如在Collections类中:

  • List – “概念”对象的接口
  • ArrayList – 接口的具体实现
  • LinkedList – 接口的具体实现
  • AbstractList – 抽象的“部分”实现来协助自定义实现

我曾经在AWT事件/侦听器/适配器范例之后做同样的事情来build模我的事件类。

标准的C#约定在Java中同样适用,它的前缀是所有接口的前缀,因此你的文件处理接口将是IFileHandler ,你的卡车接口将是ITruck 。 它是一致的,并且可以很容易地从类中告诉接口。

我喜欢接口名称,表示接口描述的合同,比如“Comparable”或“Serializable”。 像“卡车”这样的名词没有描述卡车的性能 – 卡车的function是什么?

关于惯例:我曾经在一个项目上开始,每个界面都以“I”开始。 虽然这与Java约定有些相似,但它使得查找接口非常容易。 除此之外,“Impl”后缀是一个合理的默认名称。

有些人不喜欢这个,它更像是一个.NET规范,而不是Java,但是你可以用一个大写的前缀来命名你的接口,例如:

 IProductRepository - interface ProductRepository, SqlProductRepository, etc. - implementations 

反对这个命名约定的人可能会争辩说,你不应该在乎你是在代码中使用一个接口还是一个对象,但是我发现它更易于阅读和理解。

我不会用“Class”后缀命名实现类。 这可能会导致混淆,因为你实际上可以在你的代码中使用“class”(即Type)对象,但是在你的情况下,你没有使用类对象,你只是使用一个普通的对象。

TruckClass听起来像是一类Truck ,我认为推荐的解决scheme是添加Impl后缀。 在我看来,最好的解决scheme是在实现名称中包含一些信息,在特定的实现中发生了什么(就像我们在List接口和实现中一样: ArrayListLinkedList ),但是有时你只有一个实现,并且必须具有接口到远程使用(例如),然后(如开头所述) Impl是解决scheme。

我使用两个约定:

如果接口是一个众所周知的模式(如服务,DAO)的特定实例,那么它可能不需要“I”(例如,UserService,AuditService,UserDao)在没有“I”的情况下工作正常,因为post-fix确定元模式。

但是,如果你有一个或两个(通常是一个callback模式),那么它有助于区分它与类(例如IAsynchCallbackHandler,IUpdateListener,IComputeDrone)。 这些是专门为内部使用而devise的专用接口,偶尔IInterface会提醒人们注意一个操作数实际上是一个接口,所以乍看起来立即就清楚了。

在其他情况下,您可以使用I来避免与其他常见的具体类(ISubject,IPrincipal vs Subject或Principal)冲突。