【问题标题】:Problems understanding IoC with dependency injection使用依赖注入理解 IoC 的问题
【发布时间】:2012-09-10 18:55:15
【问题描述】:

我正在努力了解 IoC w。依赖注入,我关注了 Joel Abrahamsson 的这篇博文:http://joelabrahamsson.com/entry/inversion-of-control-introduction-with-examples-in-dotnet

我的项目是这样设置的:

  • 型号
  • 接口
  • 控制器
  • DAL

我的课程如下:

汽车

public class Car
{
    public int Id { get; set; }
    public string Brand { get; set; }
    public string Year { get; set; }
}

汽车控制器

public class CarController
 {
     private readonly ICar _carInterface;

     public CarController(ICar car)
     {
         _carInterface = car;
     }

     public void SaveCar(Car car)
     {
          _carInterface.SaveCar(car);
     }
}

ICar界面

public interface ICar
{
    void SaveCar(Car car);
}

DbCar

public class DbCar: ICar
{
    public void SaveCar(Car car)
    {
        throw new NotImplementedException();
    }
}

现在,在 UI 上,我不确定如何处理它 ;-) 我可以肯定地制作我需要的 Car 对象,但是当新建 CarController 时,它(当然)需要一个ICar接口我给不了。

我有一种感觉,在阅读 Joels(伟大的)文章的过程中我误解了一些东西 :-) 我希望也许有人可以阐明我错过/误解的内容。

非常感谢任何帮助/提示!

非常感谢。

一切顺利,

【问题讨论】:

    标签: c# interface dependency-injection inversion-of-control


    【解决方案1】:

    看起来ICar 不是汽车的接口。相反,它是一个用于保存汽车的存储库的接口。所以它应该被称为ICarRepository(或者可能是IGarage。)

    你说:

    但是当新建一个 CarController 时,它(当然)需要一个 ICar 给不了的接口。

    为什么不呢?你有一个实现,DbCar。为什么你不能给它其中之一?

    你在评论中询问了这个表达式:

    new CarController(new DbCar())
    

    具体来说,通过编写该行代码,您已将控制器绑定到汽车存储库的特定实现。

    确实如此,但仅限于这种情况。您可以在单元测试的其他地方编写:

    new CarController(new FakeCarRepository())
    

    CarController 类是一个独立的模块,它对其他东西的依赖从它的构造函数的参数列表中就很清楚了。

    IoC 或“依赖注入”框架是提供标准方法来构造类的库,例如CarController,因此它需要的参数将在配置文件中指定。但这对于一个简单的应用程序来说可能有点过头了。

    【讨论】:

    • 嗨,Daniel,感谢您的意见 :-) 啊,所以 ICar 应该是数据访问层的接口而不是 Car 对象本身?然后应该将其命名为 ICarDb 之类的名称。我猜我认为它是使用接口的“正常”方式。
    • 唯一我觉得有点脏的就是在 UI 上有数据访问层对象(用于将其传递给 Controllers 构造函数)?
    • 如果UI需要获取数据,就需要访问数据访问层吧?
    • 注意,重点是给控制器一个获取数据的接口,而不是给它一个需要数据库的具体实现。这样,您可以使用假实现来构建控制器(例如)以进行测试。它不受特定于数据库的东西的约束,仅与具有从某处获取数据所需的最少方法的接口绑定。
    • 这正是我正在寻找的,但是当你这样做时: new CarController(new DbCar()) 它似乎是一个具体的类,或者只是我? ;-) 编辑:对不起,如果我对此有点慢:-)
    【解决方案2】:

    要正确进行依赖注入和控制反转,您应该坚持基于接口的开发(SOLID 原则中的“I”)。下面是我如何组织你的类和接口,以便能够最大限度地实现这一点。

    ICar界面

    public interface ICar
    {
        int Id { get; set; }
        string Brand { get; set; }
        string Year { get; set; }
    }
    

    汽车

    public class Car : ICar
    {
        public int Id { get; set; }
        public string Brand { get; set; }
        public string Year { get; set; }
    }
    

    ICarRepository 接口

    public interface ICarRepository
    {
        void SaveCar(ICar car);
    }
    

    汽车存储库

    public class CarRepository : ICarRepository
    {
        public void SaveCar(ICar car)
        {
            throw new NotImplementedException();
        }
    }
    

    ICarController 接口

    public interface ICarController
    {
         void SaveCar(ICar car);
    }
    

    汽车控制器

    public class CarController : ICarController
    {
         private readonly ICarRepository _carRepository;
    
         public CarController(ICarRepository carRepository)
         {
             _carRepository = carRepository;
         }
    
         public void SaveCar(ICar car)
         {
              _carRepository.SaveCar(car);
         }
    }
    

    那么你可以:

    ICarRepository carRepository = new CarRepository();
    ICarController carController = new CarController(carRepository);
    ICar carOne = new Car { Id = 1, Brand = "Ford", Year = "2010" };
    ICar carTwo = new Car { Id = 2, Brand = "Dodge", Year = "1999" };
    
    carController.SaveCar(carOne);
    carController.SaveCar(carTwo);
    

    【讨论】:

    • 它使用的ICar 接口接口,因为没有理由抽象DTO。你可以完全抛弃ICar 接口。
    • 不一定 - 如果您要进入一个进行自动化单元测试的环境,那么能够模拟 ICars 是必不可少的。
    • 但是你真的想模拟Car 的哪一部分?它不包含任何行为。
    • I 在 SOLID 中代表接口隔离。也就是说,您应该创建尽可能小的和特定的接口,而不是像上帝对象那样的接口。
    猜你喜欢
    • 2016-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-26
    • 2011-12-12
    • 1970-01-01
    • 2016-11-13
    相关资源
    最近更新 更多