【问题标题】:How do I deal with abstracting away 3rd party dependencies (Dependency Injection)?如何处理抽象出 3rd 方依赖项(依赖注入)?
【发布时间】:2012-08-08 22:56:06
【问题描述】:

在将 Ninject 与 ASP.NET MVC 一起使用时,抽象出 3rd 方依赖项的最佳方法是什么?

通常,我会这样做:

public interface IProductRepository
{
    IEnumerable<Product> GetProducts();
}

public class ProductRespository : IProductRepository
{
    public IEnumerable<Product> GetProducts()
    {
        ...
    }
}

然后在控制器中:

public class ProductController : Controller
{
    private IProductRepository repository;

    public ProductController(IProductRepository repository)
    {
        this.repository = repository;
    }

    ...
}

然后我使用 Ninject 将固体 ProductRepository 自动注入到控制器中。

但是如果依赖项是第 3 方,我该怎么做呢?例如,我使用的是FlickrNet

public class ProductController : Controller
{
    private Flickr flickr;

    ...
}

我希望能够将Flickr 对象抽象到一个接口中,这样我就可以使用依赖注入并简化单元测试。我知道我可以创建一个“服务”类型的接口,然后实现一个基于包装 Flickr 对象的类。

但是我必须在接口中定义一个与 Flickr 对象的每个成员相对应的成员,然后将每个成员映射到包装器对象中。而且 Flickr 对象中有很多很多的成员。

有没有更好的方法来解决这个问题?我的主要目标是在单元测试中轻松模拟 Flickr 依赖项。

【问题讨论】:

  • Flicker 对象中的方法是不是偶然虚拟的?
  • @BrianDishaw 不,他们不是。
  • 我猜这太容易了。似乎你必须包装它并创建一个接口。也许有代码生成器可以为你编写样板?
  • 这不是 DI 的问题,而是一般的架构问题。您可以将控制器声明为抽象层,也可以在实现自定义接口的 flickr 组件周围定义一个包装器。如果您的 3rd 方组件上的方法使用更多的 3rd 方类,您也需要将它们抽象出来,依此类推,直到您只剩下原始值或更多围绕 3rd 方代码的包装器。根据该组件的复杂性,这可能意味着大量的映射和包装。
  • 我同意 Sebastian Weber:这不是测试、ASP 或 ninject 的问题。这是一个架构问题,也是一个 SOLIDness 问题。考虑重新标记。

标签: asp.net-mvc unit-testing architecture dependency-injection ninject


【解决方案1】:

将我的评论升级为答案。

这不是 DI 的问题,而是一般的架构问题。您可以将控制器声明为抽象层,也可以在实现自定义接口的 flickr 组件周围定义一个包装器。如果您的 3rd 方组件上的方法使用更多的 3rd 方类,您也需要将它们抽象出来,依此类推,直到您只剩下原始值或更多围绕 3rd 方代码的包装器。根据该组件的复杂性,这可能意味着大量的映射和包装。

【讨论】:

    【解决方案2】:

    我认为包装器是正确的方法。您不必公开 3rd 方对象的每个成员 - 只需公开您需要的那些。不同的情况下使用不同的接口,包装器解决方案变得更加漂亮。

    【讨论】:

      【解决方案3】:

      我知道这篇文章不是关于单元测试的,但它提供的解决方案顺便也适用于基于模拟的单元测试。

      http://goodcoffeegoodcode.blogspot.com/2011_04_01_archive.html

      基本上,正如@Brian Dishaw 建议的那样,您需要从 FlickrNet 类中提取接口并将其注入到您的类中。

      【讨论】:

        【解决方案4】:

        唯一的目的是将 flickr .NET 抽象为更高的抽象层。比如

        interface IAlbumViewer
        {
           IEnumerable<IImage> GetImages();
        }
        
        interface IPictureUploader
        {
           string Upload(string filename, Stream image)
        }
        

        也就是说,创建特定于您的用例的接口/方法,而不是通用的 flickr 接口。您也将从中受益,因为它可以更轻松地添加对其他图像服务的支持。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-10-12
          • 1970-01-01
          • 2021-09-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-12-12
          相关资源
          最近更新 更多