如何命名不同的类/接口?
有时我没有实现信息可以添加到实现名称中-例如接口FileHandler
和类SqlFileHandler
。
当出现这种情况时,我通常使用“正常”名称为接口命名,如Truck
,然后将实际类命名为TruckClass
。
您在这方面如何为接口和类命名?
如何命名不同的类/接口?
有时我没有实现信息可以添加到实现名称中-例如接口FileHandler
和类SqlFileHandler
。
当出现这种情况时,我通常使用“正常”名称为接口命名,如Truck
,然后将实际类命名为TruckClass
。
您在这方面如何为接口和类命名?
给你的接口
命名为其实际名称。比如卡车
,而不是I卡车
,因为它不是一个I卡车
,而是一个卡车
。
在Java中,接口
是一种类型。然后你有自卸卡车
、运输卡车
、清障卡车
、水泥卡车
等实现了卡车
的类别。
当你使用接口
代替子类时,你只需将其转换为卡车
,例如List<Truck>
。在前面加上I
只是系统匈牙利方法的标记冗余性质,这只会增加更多输入代码的工作量,但并没有什么实际意义。
所有现代Java IDE都会标记接口和实现等内容,而不需要这种愚蠢的符号。不要称其为TruckClass
,这是tautology,与IInterface
的tautology一样糟糕。
如果它是一个实现,那么它就是一个类。唯一真正的例外是,总有例外情况,可能是像AbstractTruck
这样的东西。由于只有子类才能看到这个类,并且您永远不应该将其转换为Abstract
类,因此它确实添加了一些信息,即该类是抽象的以及如何使用它。您仍然可以想出比AbstractTruck
更好的名称,例如使用BaseTruck
或DefaultTruck
,因为abstract
在定义中。但是,由于Abstract
类永远不应成为任何公共界面的一部分,我认为这是一个可以接受的例外。将构造函数设置为protected
可以大大跨越这个差距。
而且Impl
后缀只是更多的噪音。更多的同义反复。任何不是接口的东西都是实现,即使是部分实现的抽象类也是如此。你要在每个Class的名称上加上那个愚蠢的Impl
后缀吗?
Interface
是公共方法和属性必须支持的约定,它也是Type信息。实现Truck
的所有内容都是Truck
的Type。
看看Java标准库本身。你看到了IList
、ArrayListImpl
、LinkedListImpl
吗?没有,你会看到List
和ArrayList
,还有LinkedList
。这里有一篇关于这个问题的不错文章。任何这些愚蠢的前缀/后缀命名约定都违反了DRY原则。
另外,如果你发现自己在向对象添加DTO
、JDO
、BEAN
或其他愚蠢的重复后缀,那么它们可能属于一个包,而不是所有这些后缀。正确封装的命名空间是自我说明的,并减少了所有这些真正糟糕的专有命名方案中毫无意义的冗余信息,大多数地方甚至都没有在内部以一致的方式遵守这些命名规范。
如果你只能想到在你的Class
名称后面加上Impl
来使其独特,那么你需要重新考虑是否需要一个Interface
。因此,当你有一个Interface
和一个单一的Implementation
,它与Interface
没有明显的区别时,在大多数情况下你可能不需要Interface
。
然而,通常为了可维护性、可测试性和模拟,最好提供接口。请参见这个答案以获取更多详细信息。
此外,参考Martin Fowler关于InterfaceImplementationPair这个主题的有趣文章。
我倾向于遵循Java Core/Sun建立的伪标准,例如在Collections类中:
List
- "概念"对象的接口ArrayList
- 接口的具体实现LinkedList
- 接口的具体实现AbstractList
- 抽象的“部分”实现,用于协助自定义实现。我曾经采用过同样的方法,将我的事件类建模为AWT事件/监听器/适配器范例。
标准的 C# 命名惯例,在 Java 中也适用,是在所有接口前加上 I
前缀——因此,您的文件处理程序接口将是 IFileHandler
,而您的卡车接口将是 ITruck
。这样做是一致的,并且易于区分接口和类。
我喜欢接口名称表明接口描述的契约内容,例如"Comparable"或"Serializable"。像“卡车”这样的名词并没有真正描述卡车的本质 - 卡车有哪些能力呢?
关于惯例:我曾经参与过每个接口都以"I"开头的项目;虽然这与Java惯例有些不同,但它使查找接口非常容易。除此之外,“Impl”后缀是一个合理的默认名称。
Comparable
,Serializable
,……),那么它应该被称为“Truckable”。 - Bert FList
应该是Listable
吗?那太荒谬了。 - user177800有些人不喜欢这样做,这更像是.NET的惯例而不是Java的,但你可以给接口命名一个大写字母I前缀,例如:
IProductRepository - interface
ProductRepository, SqlProductRepository, etc. - implementations
反对这种命名惯例的人可能会辩称,在你的代码中,你不应该关心你是在使用接口还是对象,但我发现这样做可以更容易地实时阅读和理解。
我不会给实现类取一个“Class”后缀的名称。那可能会导致混淆,因为你实际上可以在你的代码中使用“class” (即类型)对象,但在你的情况下,你并不在使用类对象,而是在使用普通的对象。
我同时使用两种命名规范:
如果接口是一个特定的已知模式的实例(例如Service、DAO),那么它可能不需要一个"I"(例如UserService、AuditService、UserDao),因为后缀确定了元模式,这些都可以正常工作。
但是,如果你有一些一次性或两次性的东西(通常用于回调模式),那么将其与类区分开来会有所帮助(例如IAsynchCallbackHandler、IUpdateListener、IComputeDrone)。这些是专门设计用于内部使用的特殊目的接口,偶尔使用"IInterface"会提醒我们操作数实际上是一个接口,因此一眼就能看出来。
在其他情况下,您可以使用"I"来避免与其他常见的具体类发生冲突(ISubject、IPrincipal vs Subject或Principal)。
TruckClass
听起来像是Truck
的一个类,我认为推荐的解决方案是添加Impl
后缀。在我看来,最好的解决方案是在实现名称中包含一些信息,说明特定实现中正在发生的情况(就像我们在List
接口和实现中所拥有的:ArrayList
或LinkedList
),但有时您只有一个实现,并且由于远程使用(例如),必须拥有接口,那么(如开头所提到的)Impl
就是解决方案。
implements
关键字的作用。如果我必须在所有类名后面都看到 Impl
,我想我会自杀。 - Robert Harvey
ITruck
,类叫做Truck
吗? - Robert Harvey