命名服务类的约定

12

我正在开发一个简单的Java应用程序,通过RESTful API对数据库进行CRUD操作。它分为三个层次:控制器层,服务层和DAO层。

通常,我为每个领域对象创建一个服务接口。比如说,User

public interface UserService {
  List<User> getAll();
  User create(User entity);
  void update(User entity) throws Exception;
  void delete(Long id) throws Exception;
}

然后我在服务类中实现该接口:

public class UserServiceImpl implements UserService { ... }

我认为这种方法有几个缺点:

  • 它强制我将具体类命名为除UserService之外的其他名称,尽管我只有一个具体实现
  • 所有不同的服务都没有实现相同的接口
  • 会有大量行为相同的接口出现

另一种方法

我会创建一个所有服务都会实现的接口:

public interface CrudService<T> {
  List<T> getAll();
  T create(T entity);
  void update(T entity) throws Exception;
  void delete(Long id) throws Exception;
}

因此,我选择了名称CrudService来传达该接口提供的功能。然后,我有一个实现该接口的具体服务类,其类型参数为User

public class UserService implements CrudService<User> { ... }

这样我的服务名称就像UserService,我认为更加清晰易读。

问题

  • 命名服务类的惯例是什么?你通常会怎么做?
  • 如果一个具体的类听起来像一个接口,我应该将其命名为UserService吗?
  • Impl后缀呢?它是否传达了关于实现的任何信息?

3
如果你知道只会有一种具体实现,那么是否真的需要一个接口,或者这只是为了追随某些人盲目称之为“最佳实践”?看看这篇有趣的文章:http://www.adam-bien.com/roller/abien/entry/service_s_new_serviceimpl_why - Olivier Masseau
1
@OlivierM。没错。大多数情况下,我在实现实际类之前创建一个接口,只是为了使用接口,因为有人告诉我“到处使用接口很好”。但是,我实际上并不希望这个接口膨胀我的应用程序,因为只有一个实现,而且很可能永远不会改变。在这里,只需要一个单一的接口来将服务绑定在一起。 - user1019830
大多数情况下,您不需要接口。例如,如果您正在使用EJB,请使用“@Stateless”、“@Stateful”或“@Singleton”注释您的bean。但是有时确实需要接口。对于EJB,如果您想要远程服务,则需要使用“@Remote”注释的接口。但不要让例外变成规则。当需要远程访问时,请创建一个仅包含您想要公开的方法的接口,并使您的bean实现它。 - cassiomolin
3
请注意,当使用像Spring这样的现代IoC框架时(现在几乎是所有"真实"web应用程序开发的情况),仍然高度建议(甚至可以说是必须的)为您的服务声明接口,因为它可以使一切变得更简单(使用框架特定语法,一般单元测试等)。 - Priidu Neemre
@OlivierMasseau 你引用的“文章”在我看来是一篇写得很差的观点文章,用来解决这个问题的 :-) - nabster
显示剩余2条评论
1个回答

7
回答你的问题:
- 对于命名服务类没有“特殊”的约定。它们是类,因此应该使用单数形式的名词,采用驼峰命名法Customer, Company, Employee, UserService, WrapperManager, FileStream等。 - 仅仅因为UserService听起来像是一个接口,并不意味着它是一个接口。如果您不想这样命名您的类,您也不必这样做。最终取决于您。 - Impl听起来难看,看起来嘈杂。不要使用它。也不要使用前缀或其他后缀。使用整个单词。记住基本原则:类是对象,所以Apple是苹果,而不是App。此外,Impl并未传达任何关于实现(业务逻辑)的信息。
有关更多信息,请查阅以下优秀的答案:

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接