在OOP设计模式中,存储库模式和服务层之间有什么区别?
我正在开发一个ASP.NET MVC 3应用程序,我正在尝试理解这些设计模式,但我的大脑却没有得到它......但是!!
答案 0 :(得分:302)
Repository Layer为您提供了更多的数据访问抽象级别。而不是写
var context = new DatabaseContext();
return CreateObjectQuery<Type>().Where(t => t.ID == param).First();
从数据库中获取单个项目,使用存储库接口
public interface IRepository<T>
{
IQueryable<T> List();
bool Create(T item);
bool Delete(int id);
T Get(int id);
bool SaveChanges();
}
并致电Get(id)
。存储库层公开了基本的 CRUD 操作。
服务层公开使用存储库的业务逻辑。示例服务可能如下所示:
public interface IUserService
{
User GetByUserName(string userName);
string GetUserNameByEmail(string email);
bool EditBasicUserData(User user);
User GetUserByID(int id);
bool DeleteUser(int id);
IQueryable<User> ListUsers();
bool ChangePassword(string userName, string newPassword);
bool SendPasswordReminder(string userName);
bool RegisterNewUser(RegisterNewUserModel model);
}
虽然存储库的List()
方法返回所有用户,但IUserService的ListUsers()
只能返回一个,用户有权访问。
在ASP.NET MVC + EF + SQL SERVER中,我有这种沟通方式:
视图&lt; - 控制器 - &gt;服务层 - &gt;存储库层 - &gt; EF - &gt; SQL Server
服务层 - &gt;存储库层 - &gt; EF 此部分适用于模型。
视图&lt; - 控制器 - &gt;服务层此部分对视图模型进行操作。
编辑:
/ Orders / ByClient / 5的流程示例(我们希望查看特定客户的订单):
public class OrderController
{
private IOrderService _orderService;
public OrderController(IOrderService orderService)
{
_orderService = orderService; // injected by IOC container
}
public ActionResult ByClient(int id)
{
var model = _orderService.GetByClient(id);
return View(model);
}
}
这是订单服务的界面:
public interface IOrderService
{
OrdersByClientViewModel GetByClient(int id);
}
此界面返回视图模型:
public class OrdersByClientViewModel
{
CientViewModel Client { get; set; } //instead of ClientView, in simple project EF Client class could be used
IEnumerable<OrderViewModel> Orders { get; set; }
}
这是接口实现。它使用模型类和存储库来创建视图模型:
public class OrderService : IOrderService
{
IRepository<Client> _clientRepository;
public OrderService(IRepository<Client> clientRepository)
{
_clientRepository = clientRepository; //injected
}
public OrdersByClientViewModel GetByClient(int id)
{
return _clientRepository.Get(id).Select(c =>
new OrdersByClientViewModel
{
Cient = new ClientViewModel { ...init with values from c...}
Orders = c.Orders.Select(o => new OrderViewModel { ...init with values from o...}
}
);
}
}
答案 1 :(得分:37)
正如Carnotaurus所说,存储库负责将数据从存储格式映射到业务对象。它应该处理如何从存储器读取和写入数据(删除,更新)。
另一方面,服务层的目的是将业务逻辑封装到一个位置,以促进代码重用和关注点的分离。在构建Asp.net MVC网站时,这对我来说通常意味着我有这种结构
[Controller]调用[repository(s)]调用[repository(ies)]
我发现有用的一个原则是在控制器和存储库中将逻辑保持在最低限度。
在控制器中,这是因为它有助于让我保持干爽。我需要在其他地方使用相同的过滤或逻辑,如果我将它放在控制器中,我就无法重复使用它。
在存储库中,这是因为我希望能够在出现更好的内容时替换我的存储(或ORM)。如果我在存储库中有逻辑,我需要在更改存储库时重写此逻辑。如果我的存储库只返回IQueryable而另一方面服务执行过滤,我只需要替换映射。
例如,我最近用EF4替换了我的几个Linq-To-Sql存储库,而那些我坚持这个原则的那些存储库可以在几分钟内被替换掉。我有一些逻辑,而不是几个小时。
答案 2 :(得分:12)
接受的答案(并且投票数百次)有一个重大缺陷。我想在评论中指出这一点,但它会被埋没在30条评论中,所以在这里指出。
我接管了一个以这种方式构建的企业应用程序,我最初的反应是 WTH ?服务层中的ViewModels?我不想改变惯例,因为多年的发展已经进入它,所以我继续返回ViewModels。当我们开始使用WPF时,它变成了一场噩梦。我们(开发团队)总是说:哪个ViewModel?真正的那个(我们为WPF写的那个)还是服务一个?它们是为Web应用程序编写的,甚至还有 IsReadOnly 标志来禁用UI中的编辑。主要的,主要的缺陷,都是因为一个词: ViewModel !!
在你犯同样的错误之前,除了上面的故事之外,还有其他一些原因:
从服务层返回ViewModel是一个巨大的禁忌。这就像说:
如果您想使用这些服务,最好使用MVVM,这里是您需要使用的ViewModel。 哎哟!
服务正在假设它们将在某个UI中显示。 如果非UI应用程序(如Web服务或Windows服务)使用该怎么办?
这甚至不是真正的ViewModel。 一个真正的ViewModel具有可观察性,命令等。这只是一个名字不好的POCO。 (请参阅上面的故事,了解名称的重要性。)
消费应用程序最好是表示层(ViewModel由此层使用),它更好地理解C#。 另一个哎呀!
请不要那样做!
答案 3 :(得分:7)
通常使用存储库作为脚手架来填充您的实体 - 服务层将出去并提供请求。您可能会在服务层下放置一个存储库。
答案 4 :(得分:2)
存储库层用于访问数据库,并有助于扩展数据库上的CRUD操作。而服务层则由应用程序的业务逻辑组成,并且可以使用存储库层来实现涉及数据库的某些逻辑。在应用程序中,最好有一个单独的存储库层和服务层。拥有独立的存储库和服务层使代码更具模块化,并使数据库与业务逻辑脱钩。