MVC设计模式,服务层的目的是什么?

28
假设我有以下存储库模式:
interface IGenericRepo<T> where T : class
{
     IEnumerable<T> GetAll();
     T GetById(object id);
     void Insert(T obj);
     void Update(T obj);
     void Delete(T obj);
     void Save();
}

interface ICustRepo : IGenericRepo<Cust>
{
     IEnumerable<Cust> GetBadCust();
     IEnumerable<Cust> GetGoodCust();
}

public class CustRepo : ICustRepo<Cust>
{
     //implement method here
}

然后在我的控制器中:

public class CustController
{
     private ICustRepo _custRepo;

     public CustController(ICustRepo custRepo)
     {
         _custRepo = custRepo;
     }

     public ActionResult Index()
     {
         var model = _custRepo.GetAll();
         return View(model);
     }

     public ActionResult BadCust()
     {
         var model = _custRepo.GetBadCust();
         return View(model); 
     }
}

基本上我的架构设计如下:

View <-> Controller -> Repo -> EF -> SQL Server

但我看到很多人这样做:

View <-> Controller -> Service -> Repo -> EF -> SQL Server

所以我的问题是:

  1. 为什么和何时需要 service layer? 难道这不是另外增加了一个不必要的层吗?因为每个非通用的方法已经实现在 ICustRepo 中了。

  2. 服务层应该返回 DTO 还是我的 ViewModel

  3. 服务层是否应该与我的存储库进行1:1映射?

我已经找了几天,但没有找到令我满意的答案。

任何帮助都将不胜感激,不好意思我的英语不是很好。

谢谢。

更新:

存储库和服务层之间的区别?

我已经阅读过这篇文章。我已经知道这两者之间的区别,但我想了解为什么和目的。因此,这并不能回答我的问题。


可能是Repository和Service Layer之间的区别?的重复问题。 - David Arno
更准确的说法是 EF -> 数据库 而不是 EF -> SQL Server,但我们明白您的意思。 - carloswm85
2个回答

30

TL;DR

  1. 请看下面的解释。
  2. 在服务层之上的层不应该“知道”服务层下面还有更多层存在。
  3. 不一定,因为你可能会发现同一种类型的数据分散在2个表中,“核心”只能看到其中一个,数据访问层负责“分组”并返回服务层类型。

解释

典型的3层架构由展示层、服务/领域层和数据访问层(DAL)组成。

将服务层视为应用程序的“核心”。通常,服务层只有存储库接口,这些接口将在DAL中实现。

因此,它允许您“轻松”切换访问数据的方式。服务层返回的对象不应该是DAO,因为毕竟,展示层甚至不知道DAL的存在。

场景: 您有一个三层解决方案。目前在拥有所有层面上并没有太多意义。

      /-------------------\
      |      Web App      | <--- Presentation Layer
      |-------------------|
      |  Service Library  | <--- Service Layer
      |-------------------|
      | Entity Framework  | <--- Data Access
      \-------------------/

现在您希望在ASP.NET MVC WebApi中拥有一个REST API

      /--------------------\
      | Web App | REST API | <--- Presentation Layer
      |--------------------|
      |  Service Library   | <--- Service Layer
      |--------------------|
      |  Entity Framework  | <--- Data Access
      \--------------------/

例如,现在你不再想使用Entity Framework作为数据访问方式,而是想使用NHibernate。

      /--------------------\
      | Web App | REST API | <--- Presentation Layer
      |--------------------|
      |  Service Library   | <--- Service Layer
      |--------------------|
      |     NHibernate     | <--- Data Access
      \--------------------/

请注意,我们添加了一种新形式的演示,并切换了访问数据的方式,但服务层从未改变。

通常,服务层公开接口供数据访问层实现,以便获得所需的“抽象”。

我在大学中使用这种体系结构实现了一个项目。您可以在此处查看代码HERE

希望这有所帮助。如果我解释得太乏味,请原谅 :P


4
请注意,我们添加了一种新的演示形式并更改了访问数据的方式,但服务层从未更改。 - tickwave
你能详细说明一下为什么服务层使用接口向客户端公开自己吗?接口似乎通常与实际的服务类是一对一的匹配,那么为什么要使用接口呢? - Halter
接口是用于数据访问层的。例如,您有一个PersonRepository接口,由数据访问实现,例如:PersonRepositoryNHibernateRepositoryImpl,您可以配置依赖注入容器以注入新模块/项目中的类。 - Driver

7

广告1:服务层应该是整个业务逻辑的放置处。这更多关于分离职责:

  • 控制器 - 负责准备 viewModel 并将其传递给特定视图,

  • 仓储库 - 抽象层负责从数据库中收集实体

  • 服务 - 负责复杂逻辑。经常出现服务使用许多实体来进行一些逻辑并仅返回 DTO 的情况。

广告2:我认为服务层应该返回 DTO 对象,应该在控制器中映射到 viewModels 中。

广告3:不是这种情况。在您的示例中,您可以将 GetBadCust 和 GetGoodCust 从 repo 移动到服务,并返回一些 DTO。


1
如果我将GetBadCustGetGoodCust以及每个逻辑操作的每种方法移动,那么仓储库将只包含基本操作,如插入、更新、删除和获取所有。这样对吗?如果是这种情况,您认为我是否应该删除所有仓储库,只保留通用的仓储库? - tickwave
1
是的,对我来说这听起来非常合理-只保留像GetAll、GetById、Insert、Update、Delete等通用方法的存储库,并将其他更“性感”的方法移到服务层。 - Piotr Czarnecki
我不是专家,但是...如果您将所有方法从repo移动到service会发生什么?例如,如果service需要GetGood(),那么它会从repo请求GetAll(例如5000个客户),然后传输到您的service,一旦在那里,service需要丢弃Bad(例如4000个)并返回Good(例如1000个),对吧?因此...随着时间的推移,您的service变得非常缓慢。想象一下更复杂的查询和企业应用程序中数据库中有更多记录的情况,您需要使用5、6个表的内部连接来获取某些值,联合和其他东西。难道直接在Repository中拥有该方法不是更好吗? - Stelios

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