我知道这个问题可能看起来像重复的一样,但请让我解释一下。
因此,我创建了几个使用可插拔架构的组件,基本上,我可以自由地添加新的实现,它们将自动为我注入和处理。在某些情况下,这确实很方便。
我将讨论最简单的一种,即验证组件。
使用这样的设计的原因之一是,我喜欢明确公开自己的角色,如Udi Dahan所述
基本上我有这样的代码:
public interface IValidatorRuner
{
void Run<TTarget>(TTarget target);
}
public class ValidatorRunenr : IValidatorRuner
{
private readonly IServiceLocator _serviceLocator;
public ValidatorRunenr(IServiceLocator serviceLocator)
{
_serviceLocator = serviceLocator;
}
public void Run<TTarget>(TTarget target)
{
// this is the dynamic/pluggable phase
// is this an antipattern???
var foundValdiators = _serviceLocator.GetAllInstances<IValidator<TTarget>>();
foreach (var valdiator in foundValdiators)
{
valdiator.IsSatisfiedBy(target);
}
}
}
此代码使我可以明确地公开我的验证规则,如下所示:
//this will allow me to create validators in this way
//and they will be automatically injected and resolved for me
//(easy, to read, easy to write, easy to test, pff I could even smoke this validator easily)
public class OneValdiationRuleExplicitlyExposedAndEasyToTest : IValidator<Person>
{
public bool IsSatisfiedBy(Person target)
{
return target.Age > 18;
}
}
public class Person
{
public int Age { get; set; }
}
public interface IValidator<TTarget>
{
bool IsSatisfiedBy(TTarget target);
}
我将使用如下代码:
//usage
public class SomeCommandHandler
{
private readonly IValidatorRuner _validatorRuner;
public SomeCommandHandler(IValidatorRuner validatorRuner)
{
_validatorRuner = validatorRuner;
}
public void SomeMethod()
{
_validatorRuner.Run(new Person{Age = 16});
}
}
验证只是一个示例,我还使用它来触发域事件并以相同的可插入方式运行管道和过滤器
以这种方式使用服务定位器是否是反模式?
我知道我可能隐藏了一些依赖关系,但事实是,这些依赖关系是在应用程序初始化时动态注入并发现的(Composition root)
您的想法将不胜感激
最佳答案
我认为,代码示例的主要问题是服务定位器本身已注入ValidatorRunner的实现中。对我来说,这是一种反模式,但也许不是您要问的那种。
我可能给出的任何答案都归结为您的服务定位器实现的功能。但是可以肯定的是,不应将其传递到类的构造函数中。相反,当您要求服务定位器实现“ IValidatorRuner”的实现时,服务定位器本身应将这些内容传递给
例如,您可以注入一个工厂,该工厂知道如何为给定类型加载动态验证器实例。