27

我在一个 Java Web 应用程序上工作,它使用 Spring 进行依赖注入,使用 JMock 在我们的单元测试中模拟这些依赖项。

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

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

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

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

4

2 回答 2

36

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

  • 使接口更通用。

    EmployeeRepository implements Repository
    DocumentMappingService implements MappingService
    
  • 将您的单个实现称为“默认值”

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

    EmployeeRepositorySupport implements EmployeeRepository
    DocumentMappingServiceSupport implements DocumentMappingService
    

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


编辑:响应用户nyxz关于-BaseorBase-约定的评论。

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

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

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

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

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

下面Adapter以 Android 框架的层次结构为例:

  • 接口层次结构。

    public interface Adapter
    public interface ListAdapter extends Adapter
    public interface SpinnerAdapter extends Adapter
    
  • abstract Base分解出常见行为和接口实现的类。

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

    public class SimpleAdapter extends BaseAdapter implements Filterable
    public class ArrayAdapter<T> extends BaseAdapter implements Filterable
    
于 2013-06-24T12:37:35.107 回答
5

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

  • 我讨厌最初的I. 它没有给图片带来任何价值。它让我想起了匈牙利表示法,其中浮点变量要加上后缀_f等。不。
  • Impl后缀足够好。但另一方面,这听起来很奇怪。

对于给定的接口,我建议两个替代建议Foo

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

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

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

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

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

编辑:至于嘲笑:

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

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

于 2013-06-24T12:25:58.117 回答