Java接口/实现命名约定
你如何命名你创build的不同的类/接口? 有时我没有实现信息添加到实现名称 – 如接口FileHandler
和类SqlFileHandler
。
当发生这种情况时,我通常以“普通”名称命名接口,如Truck
并命名实际的类TruckClass
。
你如何在这方面命名接口和类?
命名你的Interface
是什么。 Truck
。 不是ITruck
因为它不是ITruck
,而是Truck
。
Java中的Interface
是一种types 。 然后你有implement Truck
DumpTruck
, TransferTruck
, WreckerTruck
, CementTruck
等。
当你使用Interface
代替一个子类时,你只需要将它投射到Truck
。 如List<Truck>
。 把I
放在前面只是蹩脚的匈牙利风格的符号同义反复 ,只增加了更多的东西来键入你的代码。
所有现代Java IDE的标记接口和实现,还有什么不是没有这个愚蠢的符号。 不要把它TruckClass
,这是重言式,就像IInterface
重言式一样糟糕。
如果它是一个实现它是一个类。 这个规则唯一的例外就是AbstractTruck
。 因为只有子类才会看到这一点,所以你不应该投到一个Abstract
类,它会添加一些信息,类是抽象的,应该如何使用。 你仍然可以想出一个比AbstractTruck
更好的名字,而使用BaseTruck
。 但是由于Abstract
类不应该成为任何面向公共的接口的一部分,所以这个规则是可以接受的例外。 要protected
施工人员,要跨越这个鸿沟还有很长的路要走。
Impl
后缀也是更多的噪音。 更重言式。 任何不是接口的都是一个实现,甚至是部分实现的抽象类。 你打算把这个愚蠢的Impl
后缀放在每个Class的每个名字上吗?
Interface
是公共方法和属性必须支持的协议,也是types信息。 所有实施Truck
是一种Truck
。
看看Java标准库本身。 你看到IList
, ArrayListImpl
, LinkedListImpl
? 不,您会看到List
和ArrayList
以及LinkedList
。 这是一个关于这个确切问题的好文章 。 任何这些愚蠢的前缀/后缀命名约定都违反了DRY原则。
此外,如果您发现自己将DTO
, JDO
, BEAN
或其他愚蠢的重复性后缀添加到对象,那么它们可能属于一个包而不是所有这些后缀。 正确打包的命名空间是自我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
接口和实现中一样: ArrayList
或LinkedList
),但是有时你只有一个实现,并且必须具有接口到远程使用(例如),然后(如开头所述) Impl
是解决scheme。
我使用两个约定:
如果接口是一个众所周知的模式(如服务,DAO)的特定实例,那么它可能不需要“I”(例如,UserService,AuditService,UserDao)在没有“I”的情况下工作正常,因为post-fix确定元模式。
但是,如果你有一个或两个(通常是一个callback模式),那么它有助于区分它与类(例如IAsynchCallbackHandler,IUpdateListener,IComputeDrone)。 这些是专门为内部使用而devise的专用接口,偶尔IInterface会提醒人们注意一个操作数实际上是一个接口,所以乍看起来立即就清楚了。
在其他情况下,您可以使用I来避免与其他常见的具体类(ISubject,IPrincipal vs Subject或Principal)冲突。