如何命名创建的不同类/接口?
有时我没有实现信息要添加到实现名称中,例如接口FileHandler和类SqlFileHandler

何时发生这种情况时,我通常使用“普通”名称来命名接口,例如Truck并命名实际的类TruckClass

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

评论

您不调用ITruck接口,也不调用Truck类?

不好的约定是不好的,无论是谁提出的,我都读过,愚蠢的Impl后缀首先出现在IBM Developer Works文章中。

@Robert Harvey,我来自C#背景,因此我完全同意您的评论。似乎对于Java,共识是一个非常不同的约定,由user177800的答案表明。

#1 楼

将其命名为InterfaceTruck。不是ITruck,因为它不是ITruck,而是Truck

Java中的Interface是类型。那么你有DumpTruckTransferTruckWreckerTruckCementTruck等等implement Truck

使用Interface代替子类时,只需将其转换为Truck即可。如在List<Truck>中。将I放在前面只是匈牙利语风格的重言式,只会在代码中添加更多内容。

所有现代Java IDE的标记接口和实现,如果没有这种愚蠢的表示法,那将是什么。不要称它为重言式TruckClass就像IInterface重言式一样糟糕。

如果是实现,则为类。该规则唯一真正的例外(总是存在例外)可能类似于AbstractTruck。由于只有子类会看到这种情况,并且您永远都不应转换为Abstract类,因此它确实会添加一些信息,说明该类是抽象的,以及如何使用它。您仍然可以使用比AbstractTruck更好的名称,而改用BaseTruckDefaultTruck,因为定义中包含abstract。但是,由于Abstract类不应成为任何面向公众的接口的一部分,因此我认为这是该规则的可接受的例外。使构造函数protected跨越了这一鸿沟。

Impl后缀也带来了更多噪音。重言式。任何不是接口的东西都是实现,甚至是部分实现的抽象类。您是否要在每个班级的每个名称上都添加一个愚蠢的Impl后缀?

Interface是有关公共方法和属性必须支持的合同,它也是Type信息。实现Truck的所有内容都是Truck的类型。

查看Java标准库本身。您看到IListArrayListImplLinkedListImpl吗?不,您看到ListArrayList以及LinkedList。这是一篇关于这个确切问题的好文章。所有这些愚蠢的前缀/后缀命名约定都违反了DRY原则。而不是所有这些后缀。正确包装的名称空间可以自我记录,并减少这些真正构思不当的专有命名方案中所有无用的冗余信息,而大多数地方甚至在内部都不以一致的方式坚持这些专有命名方案。

如果想让DTO的名称唯一的原因是给JDO加后缀,那么您就需要重新考虑使用BEAN。因此,当您遇到一个Class和一个不是从Impl唯一专用的Interface的情况时,您可能不需要Interface

评论


如果您有不同意的答案,请发布。这些评论已经展开了广泛的讨论,这超出了他们的讨论范围。

–乔治·斯托克(George Stocker)
13年3月11日在12:23

关于单个实现的最后评论是错误的。接口仍然是一个不错的选择,也许是与同事分工,甚至为您的JUnit测试创建虚拟或伪造的实现。

– amdev
18-10-24在13:57



正确!还有一件事,因为Abstract *类型不会添加新协定,因此也应将其视为错误。拥有抽象类就是违反SRP。

– Miha_x64
19年1月10日在10:38

“因此,当您遇到一个接口和一个不是从接口唯一专用的实现时,您可能就不需要该接口。” —除非使用模拟进行测试。

–mikhailian
19年12月10日在19:53

如果您有一个扩展了Human并实现Human的John类怎么办。不能让他们两个都是人类。需要被称为HumanInterface,不是吗?

–里加
20 Sep 15'9:17

#2 楼

我在这里看到的答案表明,如果只有一个实现,则不需要接口。这与“依赖注入/控制反转”原理相违背(不要打电话给我们,我们会打电话给您!)。

所以是的,在某些情况下,您希望简化代码,并依靠注入的接口实现轻松地对其进行测试(也可能是代理-您的代码不知道!)。即使您只有两种实现-一种用于测试的Mock,另一种被注入到实际的生产代码中-这也不会使接口变得多余。记录良好的界面可建立合同,也可以通过严格的模拟实施进行维护以进行测试。

实际上,您可以建立测试,使模拟程序执行最严格的接口协定(为不应为null的参数抛出异常等),并在测试中使用更有效的实现捕获错误。生产代码(例如,由于模拟在测试中引发了异常,因此不检查不应该为null的参数是否为null,例如,由于在这些测试之后修复了代码,因此您知道参数不为null)。

对于新手来说,依赖注入/ IOC可能很难掌握,但是一旦您了解了它的潜力,便会想在各处使用它,并且会发现自己一直在建立接口-即使只有这样是一个(实际生产的)实现。

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

我也更喜欢“ Base(InterfaceName)”而不是“ Abstract(InterfaceName)”,因为在某些情况下,您希望您的基类稍后可以实例化,但是现在您的名称仍然是“ Abstract(InterfaceName)” ,这会迫使您重命名该类,可能会引起一些轻微的混乱-但是,如果始终是Base(InterfaceName),则删除abstract修饰符不会更改该类的名称。

评论


控制反转或依赖注入的概念并不需要为类的单个实现提供接口,一些流行的IoC容器实现强迫您为单个实现使用接口做一些愚蠢的事情。只需将对象传递给构造函数就是原始的“依赖注入”。至于模拟,请使用Mockito之类的东西,并根据实际类进行模拟。

–user177800
2010年5月12日,0:59



是的,然后当您在实际课程中遇到错误时,您无法将错误隔离到实际课程中。因为毕竟该类是通过使用来“测试”的。但事实并非如此。您无法通过使用实际代码来实现隔离。当两项测试失败时-一种针对该类,另一项针对使用该类的类,这有问题吗?通过接口隔离只会使一个测试失败-对实际类的测试,而不是对使用该类实现的接口的类的测试。

–MetroidFan2002
2010年5月13日,0:56

您不了解Mockito如何处理“实际班级”

–user177800
2010年5月13日,1:13

您不了解共享一个共享模拟实现以多么容易地共享以进行测试重用,而不是使用一个用于不同测试的模拟框架自定义模拟,而是每次通过安装代码重新发明轮子,这都不容易。从长远来看,自定义模拟实现更清洁,并且具有能够被记录的好处-与动态生成的代理不同。此外,除非您模拟实现类中的每个方法,否则不能保证被测单元不依赖于实际的实现-无论如何,它都应该能够工作。

–MetroidFan2002
2010年5月14日23:16

这是我对已接受答案的主要反对意见。声明一个接口绝对是有效的,即使您当前只有一个结点。通过不声明接口,所有使用者都在声明要添加或迁移到新实现时就宣布API合同已过时。

–查尔斯·艾伦
17年7月2日在14:18

#3 楼

接口的名称应描述接口代表的抽象概念。任何实现类都应该具有某种特定的特征,可以用来为其赋予一个更特定的名称。

如果只有一个实现类,并且您想不出任何使其具有特定性的东西(想要将其命名为-Impl),则似乎根本没有理由拥有一个接口。

评论


@Jay:这类事情通常是由非常正统的人完成的,他们非常孤立地对所有单元进行单元测试,并且不了解(或无法访问)允许模拟具体类的模拟框架。

– Michael Borgwardt
2010年5月12日下午6:08

@Borgwardt:我认为这是由老C程序员完成的,他们认为,就像在C中,他们必须为每个.c模块创建一个.h一样,认为在Java中他们必须为每个类创建一个接口! :-)

–杰伊
2010年5月12日13:48

将类更改为接口会破坏二进制兼容性。如果接口只有一个实现,但将来可能会有两个实现(并且向后兼容很重要),那么仍然可以将协定提取到接口类型中是明智的。

–内森(Nathan)
2012年5月5日,9:45

@Nathan:很少有项目需要二进制的向后兼容性-并且那些项目应该具有非常清晰定义和分离的公共API。

– Michael Borgwardt
2012年5月5日12:13

在要提取当前只有一个实现的接口的情况下,我想将该接口命名为尽可能简单的名称,然后在实现类的前面加上“ Default”前缀。因此,在@sdasdadas Notebook情况下,接口为Notebook,实现为DefaultNotebook。我认为这符合CoC概念,但是如果需要,可以在框架中或依赖于框架的应用程序重写(双关语意)Notebook实现。

–马丁·伍尔斯滕胡尔姆(Martin Woolstenhulme)
13年8月16日在23:10

#4 楼

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



List-“概念”对象的接口

ArrayList-接口的具体实现

LinkedList-接口的具体实现

AbstractList-抽象的“部分”实现,以帮助实现自定义实现

我曾经在AWT事件之后做同样的事情来为事件类建模/ Listener / Adapter范例。

#5 楼

标准的C#约定(在Java中也足够好用)是为所有接口添加I前缀-因此您的文件处理程序接口将为IFileHandler,而卡车接口将为ITruck。它是一致的,并且可以很容易地从类中区分接口。

评论


这只是从COM编程中获得的收益。您为什么要从类中告诉一个接口?

–约翰·托普利
2010年5月12日上午10:07

当您查看类名并且没有为您指出它的IDE时,使它脱颖而出。接口很重要,应该正确设计。

–simgineer
15年7月2日在17:31

我曾经使用C#,现在使用Java。我发现C#约定更加合乎逻辑。这个长线程向您展示了接口和植入的名称约定需要,所以说这是不需要的。

– Gal Morad
2015年10月7日14:14

如果您正在查看接口代码本身,这是明确的。如果您正在为一个接口搜索大量类,或者正在查看其他人的代码,则使接口分别可见确实有帮助。

– JamEngulfer
16-2-28在17:11

@GalMorad-逻辑谬论呼吁传统/共同实践呼吁

–user177800
17年6月23日19:21在

#6 楼

我喜欢表示接口描述的协定的接口名称,例如“ Comparable”或“ Serializable”。像“卡车”这样的名词并不能真正描述卡车的特质-卡车的能力是什么?

关于约定:我从事的项目中每个接口都以“ I”开头;尽管这与Java约定有些不同,但它使查找接口非常容易。除此之外,“ Impl”后缀是一个合理的默认名称。

评论


如果模式成立(可比较,可序列化,...),那么它应该是可运输的。

– Bert F
2010年5月11日在22:42

@罗伯特·哈维(Robert Harvey),@伯特·F(Bert F):不,问题是,卡车做什么?并且它们是否在您的特定代码中执行?例如。他们可能是“骑”。

–梅基
2010年5月11日在22:57

@Mecki-开个玩笑-我确定@Robert的评论也是如此。

– Bert F
2010年5月11日23:00



这没有任何意义,那么您建议List应该是Listable是什么呢?那太荒谬了。

–user177800
16年8月19日在1:22

@JarrodRoberson-恩...有可迭代的权利吗?我认为问题在于,这种可行方法仅适用于具有单一行为的接口。更复杂的界面实际上是组合概念,定义了一组相关行为,例如列表结合了可添加,可移动,可索引等

–查尔斯·艾伦
17年7月2日在14:10



#7 楼

有些人不喜欢它,它比Java更像.NET约定,但是您可以使用大写的I前缀来命名接口,例如:

IProductRepository - interface
ProductRepository, SqlProductRepository, etc. - implementations


反对这种命名约定的人可能会争辩说,您不必关心您是在代码中使用接口还是对象,但是我发现即时更容易阅读和理解。

我不会以“ Class”后缀来命名实现类。这可能会导致混乱,因为您实际上可以在代码中使用“类”(即Type)对象,但是在这种情况下,您不是在使用类对象,而只是在使用普通的对象。

评论


我们不需要Java中的匈牙利符号

–郭富城
2012-12-28 23:46

没有什么“更容易即时阅读和理解” ....如果您在代码“ truck.drive()”中看到,为什么要关心卡车的类型是卡车还是ITruck?您知道卡车是接口的实现,您会从中得到哪些有用的信息?没有。如果有卡车类型并且您需要专门化它,那么您要找出什么是卡车

–inor
14年8月19日在10:36

@SteveKuo mField比ISomething更傻。

– Moses Aprico
17年5月26日在4:42

这仅仅是对传统的呼吁/对普通实践的呼吁的逻辑谬误

–user177800
17-6-23在19:22



#8 楼

我使用两种约定:

如果接口是众所周知的模式(例如Service,DAO)的特定实例,则可能不需要全部使用“ I”(例如UserService,AuditService,UserDao)在没有“ I”的情况下可以正常工作,因为后缀确定了元模式。但是,如果您一次或两次执行某些操作(通常用于回调模式),那么它将有所帮助区别于类(例如IAsynchCallbackHandler,IUpdateListener,IComputeDrone)。这些是供内部使用而设计的专用接口,有时IInterface会引起人们对操作数实际上是接口这一事实的关注,因此乍一看就很清楚。

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

评论


甚至没有一贯做得很差:-)

–user177800
2010年5月11日23:02



那些“ Service”和“ DAO”后缀应该是软件包,那么您也不需要那个无用的后缀。

–user177800
2010年5月11日23:23

我真的没有发现软件包资格可以在可读性方面澄清任何事情(尽管从技术上讲它会消除歧义)。考虑休眠的Session与那里的其他Session发生冲突。两者兼有的任何代码都难以思考和阅读。

–贾斯汀
2010年5月11日23:31

使用包名“ DAO”只是愚蠢的。这意味着其中只有DAO类,但实际上我可能也希望在其中有我的领域对象。为什么不将卡车,PickupTruck和TruckDao放入“卡车”包装中?实际上,如果您与该TruckDao交互,则意味着您以后可以通过其他方式拉卡车。不知道为什么要对它进行具体分类。

–尼克
13年5月8日在21:05

#9 楼

TruckClass听起来像是Truck的一类,我认为建议的解决方案是添加Impl后缀。我认为最好的解决方案是在实现名称中包含一些信息,该信息具体实现时会发生什么情况(例如List接口和实现:ArrayListLinkedList),但是有时您只有一个实现并且必须有接口到远程使用(例如),然后(如开头所述)Impl是解决方案。

评论


类不需要后缀即可表明它们是接口的实现;这就是Implements关键字的用途。如果我必须在所有班级名称后都看到Impl,我想我会自杀。

–罗伯特·哈维(Robert Harvey)
2010年5月11日在22:28



常见并不意味着与正确无异,罗伯特·哈维(Robert Harvey)100%正确。

–user177800
2010年5月11日在22:29



@Robert Harvey那么,如果我的接口只有一个实现且名称中没有具体信息,该怎么办?

–阿米尔(Amir Rachum)
2010年5月11日在22:32

@Robert Harvey如果接口将代表普通车辆并且卡车是车辆的“专业化”,那就很好了。但这恰好只是卡车公司软件的一个例子。因此在使用该界面时应该说卡车。否则就是尴尬。

–阿米尔(Amir Rachum)
2010年5月11日在22:44

如果您有一个实现和一个接口,则可能不应该具有一个接口。

–user177800
2010年5月11日23:25