我有一个要实例化的类 MyClass
,它包含一个私有(private)属性 ObjectRepository
,我想在 MyClass
的构造函数时实例化它> 被调用。
public MyClass
{
private ObjectRepository _objectRepository;
public MyClass()
{
}
}
MyClass
被实例化以添加到列表中:
objects.Add(new MyClass());
遵循 SOLID 原则最干净的方法是什么?
----编辑----
我还忘记提及的是,当我为 MyClass
编写单元测试时,我希望能够模拟 ObjectRepository
。当 ObjectRepository
从 MyClass
的构造函数实例化时,这是不可能的,因为在测试中没有对 _objectRepository
的引用可用。
最佳答案
为此,您需要查看 SOLID 中的 D:依赖倒置。
MyClass
需要一个 ObjectRepository
的实例来完成它所做的一切;它对 ObjectRepository
具有依赖性。根据依赖倒置原则,它应该依赖于抽象,而不是具体类型。在 C# 中,执行此操作的通常方法是使用接口(interface),例如 IObjectRepository
,其中包含 MyClass
需要的所有方法,但除此之外别无其他。也可以使用抽象基类来完成,但这不太常见。
当然,如果你依赖于一个接口(interface),你不知道实现它的具体类型,所以你不能实例化它。这可以;您只需要提供一个实例即可。
public MyClass
{
private IObjectRepository _objectRepository;
public MyClass(IObjectRepository objectRepository)
{
_objectRepository = objectRepository;
}
}
现在,当您创建 MyClass
的实例时,您必须为其提供实现 IObjectRepository
的东西。
objects.Add(new MyClass(new ObjectRepository()));
在很多情况下,这就足够了。但是,对于大型对象图,像这样手动创建所有内容可能既费力又重复。解决这个问题的通常方法是使用像 IoC 容器这样的依赖注入(inject)服务。 IoC 代表控制反转,因为你正在反转事物的创造。 IoC 容器不是实例化顶部的东西并让每个东西创建它需要的东西,而是从底部开始,创建需要的东西,然后使用它来创建依赖它的东西,等等。您可以如何使用它的示例如下:
var container = new SomeIoCContainer();
container.For<IObjectRepository>().Use<ObjectRepository>();
var myClass = container.Resolve<MyClass>();
(示例语法;这在不同的 IoC 容器之间有所不同,但它们通常是这样的。)
在许多情况下,您会发现 IoC 容器可以集成到您的应用程序中,这意味着您甚至不需要显式调用容器来解决问题。例如,ASP.NET 就是为此而构建的,因此一旦配置了容器,您只需将构造函数参数添加到 Controller ,框架就会使用容器为您提供这些参数。
这种方法的优点:
- 如果你想测试
MyClass
中发生的事情,你可以简单地给它一个假的IObjectRepository
版本,它不会做任何复杂的事情,这样你可以用更少的工作设置您的测试,并且您知道您在MyClass
上的测试不会受到ObjectRepository
中可能发生的不相关事情的影响。您可以通过为测试设置一个单独的容器来完成此操作,但通常手动执行此操作更容易 - 您只测试一件事,而您的模拟依赖项不应该依赖于任何东西。 - 随着您的应用程序的增长和变得越来越复杂,您不必担心如何创建事物所依赖的所有组件 - 您只需告诉您的 IoC 容器它们是什么,它就会负责创建事物。
- 如果您需要更改其中一个依赖项的工作方式,那就容易多了。例如,如果您有一个从 SQL 数据库获取对象的
DatabaseObjectRepository
,并且您想要将其替换为一个从 Web 服务获取对象的WebClientObjectRepository
,您只需实现相同的接口(interface)并更改您告诉容器将什么用于IObjectRepository
的那一行,它就会为您交换应用程序中的所有用法。
关于c# - 使用也需要实例化的私有(private)对象实例化类的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56126111/