问题 MVC设计模式,服务层目的?


假设我有以下回购模式:

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映射吗?

我环顾了几天,但我对答案并不满意。

任何帮助将不胜感激并为糟糕的英语道歉。

谢谢。

更新:

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

我已经读过了。我已经知道那些2之间的区别,但我想知道为什么和目的。所以这不回答我的问题


12020
2017-07-02 09:30


起源

可能重复 存储库和服务层之间的区别? - David Arno


答案:


TL; DR

  1. 见下面的解释
  2. 服务层之上的层不应“意识到”服务层下面存在更多层。
  3. 不一定,因为您可以拥有分散在2个表中的1个类型的数据,而“核心”只看到1个,数据访问层负责“分组”并返回服务层类型

说明

典型的3层体系结构由表示层,服务/域层,数据访问层(DAL)组成。

将服务层视为应用程序的“核心”。 Tipical Service Layer仅具有将在DAL中实现的存储库接口。

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

场景: 你有一个3层的解决方案。目前在拥有所有图层方面没有多大意义。

      /-------------------\
      |      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
      \--------------------/

请注意,我们添加了一种新形式的Presentation并切换了访问Data的方式,但Service Layer从未更改过。

Tipically Service Layer公开了要在数据访问层中实现的接口,因此我们得到了我们想要的“抽象”。

我在大学实施了这个架构的项目。你可以查看代码 这里

我希望这有帮助。对不起,如果我很无聊@解释事情:P


13
2017-07-02 10:42



“请注意,我们添加了一种新的Presentation形式,并改变了我们访问数据的方式,但服务层从未改变过。”这就是我所需要的一切。谢谢! - warheat1990
您能详细说明服务层使用接口向客户端公开自身的原因吗?接口似乎通常是与实际服务类的1:1匹配,为什么要打扰接口呢? - Halter
接口用于数据访问层。例如,您有一个由数据访问实现的PersonRepository接口,例如:PersonRepositoryNHibernateRepositoryImpl,您可以配置依赖注入容器来注入新模块/项目中的类。 - Driver


Ad.1服务层应该是整个业务逻辑的位置。它更多的是关于单独的责任:

  • Controller - 负责准备viewModel并传递给特定视图,

  • 存储库 - 负责从DB收集实体的抽象层

  • 服务 - 负责复杂的逻辑。通常情况下,服务使用许多实体来制作一些逻辑并仅返回DTO。

Ad.2在我看来,服务层应该返回应该映射到控制器中的viewModels的DTO对象。

Ad.3不是这样的。在您的示例中,您可以将GetBadCust和GetGoodCust从repo移动到服务并返回一些DTO


2
2017-07-02 09:42



如果我搬家 GetBadCust, GetGoodCust 每个逻辑操作的每个方法,然后repo将只包含插入,更新,删除,GetAll等基本操作。是对的吗?如果是这样的话,你认为我可能会删除所有回购并且只保留Generic吗? - warheat1990
是的,对我来说这听起来很合理 - 只使用以下方法保留通用仓库:GetAll,GetById,Insert,Update,Delete和其他更“性感”的方法转移到服务级别。 - Piotr Czarnecki