所以这是我的课程的简化版本。我有两个实现服务接口的类。一个是我的实际实现,一个是我的模拟 我需要在Worker类中创建此服务类的X个新实例。
如何告诉我的工人类我想使用哪种IService?
嘲笑工人阶级是唯一的路线吗?有更好的路线吗?
修改 因此,在阅读了一些回复之后,我觉得我没有准确地表达我的情况。我过分简化到了阻碍的地步。无论如何,我添加了更多代码,可能有助于解释我发生了什么。
我将原始的Worker
课程更改为Manager
,并且拥有Workers
的子列表。工作列表是从Manager
类创建的,我使用IService
构建它们,我想通过一个具体的OR Mock实现。然后我将开始工作人员做一些涉及IService
的事情以及我提供的变量。 (在这种情况下,它只是一个整数,但在现实生活中它是一个类)。
public interface IService
{
int a { get; set; }
}
public class Concrete : IService
{
public int a { get; set; }
float x;
public Concrete(int A)
{
a = A;
x = 0.500F;
}
}
public class Mock : IService
{
public int a { get; set; }
float x;
public Mock(int A)
{
a = A;
x = 0.750F;
}
}
public class Manager
{
List<Worker> Workers = new List<Worker>();
void CreateList()
{
for (int i = 1; i <= 3; i++)
{
Worker w = new Worker(new IService(i)); //<-- Need help here!
theList.Add(w);
}
KickOffWorkesAsync();
}
void KickOffWorkesAsync()
{
// process the workers async
}
}
public class Worker
{
IService _iService;
public Worker(IService _iSer)
{
_iService = _iSer;
}
void DoSomething()
{
//do work with _iService
}
}
答案 0 :(得分:2)
这是Dependency Injection派上用场的地方。您需要设计您的类以从外部获取它们的依赖关系,而不是自己创建它们。
类似的东西:
public class Worker
{
public Worker(IService service)
{
this.service = service;
}
public void DoSomething()
{
DoSomethingWith(service);
}
}
然后在测试中,您可以创建一个注入了模拟服务的Worker
实例,而在生产代码中,您将使用实际服务。
使用依赖注入时,有助于使用DI容器(有时也称为控制容器的反转)来正确连接相关服务,而不是手动创建依赖关系图。一些常见的DI容器用于.NET包括Ninject,StructureMap,Castle Windsor和Microsoft的Unity。
如果您之前从未使用过DI,那么这是一个相当典型的转变,但它本质上是一个简单的改变,可以为您的代码设计带来奇迹(原因很多,不是只是为了测试)。
答案 1 :(得分:2)
另一种方法是为worker提供一个工厂方法来创建服务:
public class Worker
{
private Func<int, IService> createService;
public Worker(Func<int, IService> createService)
{
this.createService = createService;
}
然后工人可以这样做:
void DoSomething()
{
var theList = new List<IService>();
for (int i = 1; i <= 3; i++)
{
IService s = createService(i); // Invoke the provided factory method
theList.Add(s);
}
// do something with the list...
}
并且单元测试可以像这样创建工作者:
public void SomeTestMethod()
{
var worker = new Worker(CreateMockService);
}
private IService CreateMockService(int arg)
{
return new Mock(arg);
}
生产代码将提供创建实际服务的工厂方法。
答案 2 :(得分:0)
尽可能简单地回答你的问题。
void DoSomething()
{
var theList = new List<IService>();
for (int i = 1; i <= 3; i++)
{
//use this
IService s = new Concrete(i);
//or this
//IService s = new new Mock(i);
theList.Add(s);
}
// do something with the list...
}
但更好的方法是使用某种类型的依赖注入或工厂(如其他答案所解释的),因此您可以在配置文件或应用启动中指定您想要的IService
使用