繁体   English   中英

新的MVC3项目中的InversionOfControl

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM