用需要实例化的私有对象实例化类的最佳方法

Bun*_*nut 1 c# solid-principles

我有一个MyClass要实例化的类,该类包含一个私有属性ObjectRepository,该私有属性在MyClass调用的构造函数时要实例化。

public MyClass
{
    private ObjectRepository _objectRepository;

    public MyClass()
    {

    }
}
Run Code Online (Sandbox Code Playgroud)

MyClass 实例化以添加到列表中:

objects.Add(new MyClass());
Run Code Online (Sandbox Code Playgroud)

遵循SOLID原则,最干净的方法是什么?

- - 编辑 - -

我还忘了提到的是,当我编写单元测试时,MyClass我希望能够进行模拟ObjectRepositoryObjectRepository从的构造函数实例化时,这是不可能的MyClass,因为测试中没有对的引用_objectRepository

ana*_*der 5

为此,您需要查看SOLID中的D:依赖关系倒置

MyClass需要一个实例ObjectRepository来做任何事情;它有一个依赖ObjectRepository。根据依赖倒置原则,它应改为依赖抽象而不是具体类型。在C#中,执行此操作的通常方法是使用接口(如)IObjectRepository,该接口上具有所需的所有方法MyClass,但仅此而已。也可以使用抽象基类来完成,但这并不常见。

当然,如果您依赖于接口,那么您将不知道实现该接口的具体类型,因此无法实例化它。这可以; 您只需要提供一个实例即可。

public MyClass
{
    private IObjectRepository _objectRepository;

    public MyClass(IObjectRepository objectRepository)
    {
        _objectRepository = objectRepository;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,当您创建的实例时MyClass,必须为其提供实现的东西IObjectRepository

objects.Add(new MyClass(new ObjectRepository()));
Run Code Online (Sandbox Code Playgroud)

在许多情况下,这就足够了。但是,对于大型对象图,像这样手动创建所有内容可能既费力又重复。解决此问题的通常方法是使用类似IoC容器的依赖项注入服务。IoC代表控制权的反转,因为您正在颠倒事物的创造。IoC容器不是实例化顶部的内容并让每个事物创建它所需的事物,而是从底部开始,创建所需的事物,然后使用该容器创建依赖于它的事物,依此类推。有关如何使用它的示例如下:

var container = new SomeIoCContainer();
container.For<IObjectRepository>().Use<ObjectRepository>();

var myClass = container.Resolve<MyClass>();
Run Code Online (Sandbox Code Playgroud)

(示例语法;这从一个IoC容器到另一个IoC容器有所不同,但是它们通常是这样的。)

在许多情况下,您会发现IoC容器可以集成到您的应用程序中,这意味着您甚至不需要显式调用容器来解决问题。例如,ASP.NET是为此目的而构建的,因此,一旦配置了容器,就可以将构造函数参数添加到控制器中,框架将使用该容器为您提供这些参数。

这种方法的优点:

  • 如果你想测试发生的事情里面MyClass,你可以简单地给它的仿版IObjectRepository是不会做任何事情复杂,让你可以设置你的测试少得多的工作,你知道你在考试MyClass韩元”不受内部可能发生的不相关事物的影响ObjectRepository。您可以通过为测试设置一个单独的容器来执行此操作,但是通常手动操作更容易-您仅测试一件事,并且您的模拟依赖项不依赖任何内容。
  • 随着应用程序的增长和变得越来越复杂,您不必担心如何创建事物所依赖的所有组件-您只需告诉IoC容器它们是什么,它将负责创建事物。
  • 如果您需要更改其中一个依赖项的工作方式,它会容易得多。例如,如果您有一个DatabaseObjectRepository从SQL数据库获取对象的,而又想将其交换为WebClientObjectRepository从Web服务获取对象的a,则只需实现相同的接口,然后更改告诉容器的那一行用作IObjectRepository,它将为您交换应用程序中的所有用法。