[英]InversionOfControl in a new MVC3 project
我正在使用C#,MVC3,实体框架4构建一个电子商务网站,这是我对MVC3和实体框架的第一次尝试,所以我想确保一个健全的架构。 特别是,我正在质疑我对Interfaces和Dependency Inversion的使用,因为它们与Services和Repository层有关。 为了简洁和清晰起见,我将专注于系统的一个区域,即推车系统。
这是一个接口反转示例,PluralSite用于解释在不考虑适当依赖性的情况下创建接口的典型趋势。
假设您有一个“BoxingMatch”类所依赖的IKangaroo接口。 当你添加更多“拳击手”时,比如IMikeTyson和IJoeBoxer,你现在有三个不同的界面,每个拳击手一个,“BoxingMatch”需要知道。 IKangaroo,IMikeTyson和IJoeBoxer每个只有一个具体的实现,这意味着你甚至不需要那些接口(你也可以让BoxingMatch直接依赖于具体的袋鼠,MikeTyson和JoeBoxer类)。 此外,IKangaroo或IMikeTyson的实施方案甚至没有意义。 因此接口是不必要的,并且不会给架构带来任何价值。
在此示例中反转依赖项将导致“BoxingMatch”定义将要使用的类(Kangaroo,MikeTyson和JoeBoxer)将要实现的接口。 因此,“BoxingMatch”将依赖于IBoxer接口,Kangaroo,MikeTyson和JoeBoxer都将实施IBoxer。 有反转,它是完全有道理的。
现在,我的情况...... CartController构造函数有两个依赖参数注入,ICartService和IProductService)。 CartService采用单个注入的构造函数参数(ICartRepository)。 CartController在CartService上调用AddItem(),CartService在CartRepository上调用AddItem()。
ICartRepository有两个实现:CartRepository(在主Web项目中)和TestCartRepository(在Tests项目中)。 ICartService只有一个实现。
我的问题:我的架构如何与上例中的课程相结合? 我真的没有看到我的CartController如何比CartService更少耦合。 控制器仅依赖于CartService,而不依赖于ICartRepository。 因此,我可以通过让CartController定义哪个接口CartService和ICartRepository将使用来反转控制,因为CartService和CartRepository完全是不同的层。 我对么?
下一级,同一个问题。 CartService依赖于CartRepository。 上述反演原则是否适用于此? 或者我已经通过在CartService构造函数中要求ICartRepository注入参数来反转依赖关系?
所以我的问题是,我做到了这个“正确”吗?
任何想法或建议将不胜感激。
我的代码,供参考:
CartController:
//constructor
public CartController(ICartService cartService, IProductService productService)
{
_cartService = cartService;
_productService = productService;
}
public RedirectToRouteResult AddItem(Cart cart, int productId)
{
var product = _productService.GetProduct(productId);
if (product != null)
{
_cartService.AddItem(cart, product, 1);
}
return RedirectToAction("Index");
}
CartService(实施):
//constructor
public CartService(ICartRepository repository)
{
_repository = repository;
}
public void AddItem(Cart cart, Product product, int quantity)
{
//simplified for brevity
var cartProduct = _repository.CartProducts().SingleOrDefault(cp => cp.CartId == cart.CartId && cp.ProductId == product.ProductId);
_repository.AddCartItem(cartProduct);
}
购物车存储库(实施):
public void AddCartItem(CartProduct cartProduct)
{
_context.CartProducts.Add(cartProduct);
_context.SaveChanges();
}
你错误地认为使用IoC的唯一原因是提供多种实现。 实际上,这是使用IoC最不实用的原因之一。
通过使用IoC容器,您可以管理对象生存期(例如,通过在单个Web请求的生命周期中使对象生效)。
IoC容器还处理递归依赖项。 如果你创建一个IMikeTyson并且IMikeTyson依赖于IBoxingShorts,那么你不必实例化拳击短裤,它们是免费的。
所有这些都忽略了使用IoC的重要原因,那就是让单元测试变得更容易。 通过使用接口,您可以为BoxingMatch的单元测试提供模拟IMikeTysons,以便您可以提供BoxingMatch已知值,而不必在每次测试后重置数据库。
而且,基于IoC和接口的编程还有大约100个其他好处。
我认为你正在过度思考Cart的情景。 您只需要传递您所依赖的实例,而不必过分关注IoC的学术定义。
这可能无法回答您的所有问题,但如果您确实打算在Controller和Service层之间分离流程,例如使用WCF,那么您的I *服务将成为WCF服务合同 - 这将加强对夫妇的决定通过接口层而不是直接耦合到类。
在这种情况下,可以添加额外的Facade /间接(通常称为服务代理),从而从控制器隐藏“确切的”SOA服务接口。 这将允许服务层被类似功能之一替换,但使用不同的服务接口。
您的反转看起来很好 - 您的图层依赖于抽象(接口)并隐藏实现,因此* Service不会意识到存储库使用了Entity Framework,NHibernate或DataSets,Controller也不知道服务层使用了存储库,或直接访问数据库(注入构造函数不会暴露在图层客户端使用的接口上,所以不用担心这里)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.