【问题标题】:Java Interface Naming Conventions [closed]Java 接口命名约定 [关闭]
【发布时间】:2023-04-11 12:21:01
【问题描述】:

我正在开发一个 Java Web 应用程序,该应用程序使用 Spring 进行依赖注入,并使用 JMock 在我们的单元测试中模拟这些依赖项。

目前,我们的团队在如何命名我们使用的某些接口方面存在一些不同的意见。我们对域中具有多个实现的接口进行命名没有问题,这很简单。但是,当涉及到我们只有一个实现并且打算在未来只实现一个的接口时,我们遇到了障碍。

我们有这样的接口纯粹是为了模拟,例如,我们有我们在单元测试中模拟出来的服务和存储库,这些服务将被命名为“DocumentMappingService”或存储库“EmployeeRepository”。目前,有些人只是在关联的接口名称前加上“I”,即“IDocumentMappingService”和“IEmployeeRepository”。其他人像我上面那样命名接口,然后在实现类的接口名称后附加一个“Impl”。

第三个“派系”觉得这两个选项都很差。看看著名的“Growing object-oriented software,guided by testing”之类的文献会让人相信前面提到的两个选项都很糟糕,接口名称应该清楚地定义契约和实现类名称应明确说明该合同是如何实施的。不过,在我上面提到的情况下,我们发现这很难做到。

我希望那里有人以前遇到过类似的问题,并对哪个选项最好以及为什么有一些建议。另外,如果您认为“I”和“Impl”选项都很差,那么请提出一个具体的替代约定。

【问题讨论】:

  • 这对程序员来说可能更好......但我对此表示怀疑。根本不可能有客观正确的答案。 SO 不是一个讨论论坛。
  • 对“Impl”的普遍批评是,在所有课程上都使用相同的东西没有意义。实现类的名称应该反映实现。例如,ArrayList 中的“数组”以及LinkedList 中的“链接”。我不认为“Impl”/“Default”会特别引起问题(直到第二次实现),但这不是最好的。
  • 如果你的接口纯粹是为了模拟,也许使用更好的模拟框架?我猜你正在使用 JMock - 抛弃所有这些接口并尝试使用 Mockito 或 EasyMock 之类的替代方法?
  • 尽管这个问题被关闭了,但我得到了我想要的答案,并且支持和收藏的数量表明至少有一些其他成员也认为这很有用。

标签: java interface naming-conventions


【解决方案1】:

这里没有“一个”正确答案。命名是相当主观的,但最重要的是它应该在整个代码库中一致。我只想为您添加(@fge 的回答)更多选项:

  • 使接口更通用。

    EmployeeRepository implements Repository
    DocumentMappingService implements MappingService
    
  • 调用你的单一实现“defaults”

    DefaultEmployeeRepository implements EmployeeRepository
    DefaultDocumentMappingService implements DocumentMappingService
    
  • 将您的基本实现(如果,有时是扩展)称为“支持”

    EmployeeRepositorySupport implements EmployeeRepository
    DocumentMappingServiceSupport implements DocumentMappingService
    

我在使用 Spring 框架 时经常遇到这些命名约定。


编辑: 回应用户 nyxz-BaseBase- 约定的评论。

就像我之前说的,命名是主观的,这样使用Base 命名法并没有错。但是,就个人而言,我不喜欢使用它。原因如下:

  1. 如果您的实现主要是直接使用,那么实例化类的代码会留下破坏 OOP 层次结构的印象。那也许应该实例化一个特定的派生类。

  2. 如果您的实现主要是从扩展而来,那么Base 这个词在某种程度上就变得多余了。您是从它扩展而来的,所以当然,它是一个基类。呵呵!

第 2 点主要适用于项目中的外围类。您在发布要在其他项目中使用和扩展的框架或库时提供的扩展点。

另一方面,使用Base 术语的一个很好的用例是用于框架内部的类,这些类将通用功能排除在其他外围类之外。因为这些类不应该被直接实例化,所以它们被标记为abstract,这与第一个点一致。

以下是来自 Android 框架的 Adapter 层次结构示例:

  • 接口层次结构。

    public interface Adapter
    public interface ListAdapter extends Adapter
    public interface SpinnerAdapter extends Adapter
    
  • abstractBase 类将常见行为和接口实现分解。

    public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter
    
  • 大部分实例化但有时由 Android 应用程序扩展的外围类。

    public class SimpleAdapter extends BaseAdapter implements Filterable
    public class ArrayAdapter<T> extends BaseAdapter implements Filterable
    

【讨论】:

  • 这些都是很好的建议,Ravi,谢谢。我也看到了第二个建议(即默认)。至于第一个建议, MappingService 可以工作,但我不认为 Repository 对我们有用,因为并非我们所有的存储库都具有完全相同的合同,所以它被抽象得太远了。第三个选项(即支持)让我很感兴趣,我以前从未见过。您是从哪里看到的,使用“支持”一词的原因是什么?
  • Spring Framework 大量使用“支持”类。例如,要编写自定义属性编辑器(在 Spring.xml 中转换自定义对象的字符串表示形式),我们扩展 PropertyEditorSupport。使用 Spring JDBC 时,建议所有 DAO 扩展 JdbcDaoSupport
  • 我真的很喜欢拉维的建议,谢谢。我已经给了你一个加 1,如果没有人很快提出更好的建议,那么我会接受你的回答
  • 我想知道您对 -Base 或 Base- 约定有何看法?前任。接口 EmployeeRepository 和 BaseEmployeeRepository 或 EmployeeRepositoryBase。我在一个代码中看到过这几次。
  • @nyxz 我已将我对Base 类命名约定的想法添加到我的答案中。我实际上更喜欢EmployeeRepository implements Repository 而不是BaseEmployeeRepository implements EmployeeRepository。在定义一个非常通用的Repository 接口不可行的情况下,您可以使用像EmployeeRepository&lt;Employee&gt; implements Repository&lt;Employee&gt; 这样的泛型。
【解决方案2】:

这样一个问题的答案只能反映回答者的口味......所以这些是我的口味:

  • 我讨厌最初的I。它没有给图片带来任何价值。它让我想起了匈牙利符号,其中浮点变量以_f 或类似名称作为后缀。没有。
  • Impl 后缀就足够了。但另一方面,这听起来很奇怪。

对于给定的接口Foo,我建议两个备选方案:

  • 创建单个实现,但不使用Impl 后缀;找到一个更“吸引人”的名字。比如TheOnlyOneFoo;
  • 创建带有附加s: Foos 的工厂。那么,Foo 实例将是 Foos.newInstance(whatever, args)

我更喜欢第二种解决方案,原因有两个:

  • 它可以隐藏 real 实现的名字丑陋的事实;
  • 当你有一天意识到“不,毕竟有不止一个实现”时,它可以很容易地扩展:只需添加另一个静态工厂方法;如果现有的唯一现有方法听起来太笼统,您可以将其标记为@Deprecated

它甚至可以以某种方式使用,以便所有Foo 实现都是本地包,甚至是工厂私有的。但是堆栈跟踪看起来会更糟......

那里没有真正的解决方案;)

编辑:至于模拟:

  • 我推荐 mockito。真的。它非常易于使用,而且功能非常强大。
  • 如果这些是您正在处理的“单一实现类”,也许 JDK 本身有更好的选择?你到底想做什么? JDK 有隐藏的宝藏...

最后一点...您是否考虑过构建器模式?

【讨论】:

  • 我并不热衷于从 JMock 进行更改,到目前为止我对它感到满意,并且必须创建一个接口不是主要问题,我只是想要一种一致的逻辑方式来命名这些接口。当你问我到底想做什么时,这正是我在问题中所说的。我有在单元测试中模拟出来的服务和存储库,因此需要一个接口(由于 JMock)。我在问是否有人在同一条船上,以及他们为这些接口推荐的命名约定。在这种情况下,I/Impl 可能就足够了,只是想看看是否有人知道更好的方法。
  • 好的,但是说真的:你应该考虑mockito。 Jmock 赶不上 ;)
  • 我们确实在我们的测试中使用构建器来构建实体等,但我没有遵循您在这种情况下的意思。你能再解释一下吗?假设我有一个单元测试测试 XYZService 上的一个方法,该方法依赖于 ABCRepository(即 ABCRepository 自动装配到 XYZService 中),因此我需要在我的测试中模拟 ABCRepository。您建议如何使用构建器模式来完成这项工作?
  • 好吧,将ABCRepository 模拟传递给您的构建器...还是我误解了意图?
  • 但是当你将这个 repos 连接到你的服务中时(即在你的“生产”代码中),你仍然会使用“丑陋”的接口名称来连接它。或者您是否建议将构建器也用于生产代码,然后您完全放弃将依赖项直接自动装配到服务中?如果我完全错过了您在这里的建议,我深表歉意。
猜你喜欢
  • 2010-10-15
  • 1970-01-01
  • 2011-02-18
  • 2014-04-30
  • 2010-12-18
  • 2016-12-15
  • 2010-10-29
  • 1970-01-01
  • 2016-09-27
相关资源
最近更新 更多