public interface ITaskProvider
{
T GetTask<T>();
}
在下面的ITaskprovider实现中,如您所见,IUserTask和 IIdentityTask是从属性而不是构造函数注入的。 原因是Windsor自动实例化注入的属性 在访问运行时,以便我不必将所有必须注入的依赖项 在构造函数中。
public class TaskProvider : ITaskProvider
{
public IUserTasks UserTasks { get; set; }
public IIdentityTasks IdentityTasks { get; set; }
public T GetTask<T>()
{
Type type = typeof(T);
if (type == typeof(IUserTasks)) return (T)this.UserTasks;
if (type == typeof(IIdentityTasks)) return (T)this.IdentityTasks;
return default(T);
}
}
在控制器中,我在构造函数中注入ITaskProvider。
public ITaskProvider TaskProvider { get; set; }
public AuctionsController(ITaskProvider taskProvider)
{
TaskProvider = taskProvider;
}
在这里我称taskprovider及其方法很好。
public ActionResult Index()
{
var userTasks = TaskProvider.GetTask<IUserTasks>();
var user = userTasks.FindbyId(guid);
}
到此为止,一切正常。
我被告知这更像是服务定位器模式,并且违反了依赖注入模式,我想知道这里违反了什么。
答案 0 :(得分:4)
对我来说,代码中没有违反DI的问题,关于wikipedia:
将行为与依赖性解析分开的核心主体
但是坏的一面你的控制器有太多的知识,在某些情况下(如果你没有仔细编程)你可能会违反Law Of Demeter
看看你的代码:
public ActionResult Index()
{
var userTasks = TaskProvider.GetTask<IUserTasks>();
var user = userTasks.FindbyId(guid);
}
答案 1 :(得分:2)
如果控制器需要一个IUserTasks
实例,那么如果它直接从容器中收到一个实例就会更简单。从本质上讲,TaskProvider
只是容器的包装器,因为它是从UserTasks
和IdentityTasks
实例获取的。
答案 2 :(得分:2)
您正在使用依赖注入将有效的“服务定位器”注入控制器,而不是注入IUserTasks和IIdentityTasks的实现。
你的实际控制器确实依赖于IUserTasks和IIdentityTasks,但是你不是直接将它们注入你的控制器而是决定使用“服务定位器”或任务提供程序,因此你已经注入了对服务定位器的依赖,在示例中似乎只提供直接注入真正的依赖项无法完成的任何事情。
答案 3 :(得分:1)
您应该将IUserTask和IIdentityTask注入控制器的构造函数中,因为使用TaskProvider没有任何好处。除此之外,在你这样做的过程中,你会错过一些编译时检查。例如,您可以调用TaskProvider.GetTask()并等待在运行时爆炸。至少应该对该泛型参数设置一些约束(如果两个接口都可以从公共父继承)。
关于“违规”,您应该注意到您没有将依赖项注入控制器。您正在提供一种检索它们的方法。