最近我读了很多关于应用程序设计模式的东西:关于DI,SL反模式,AOP等等。其原因 - 我想达成设计的妥协:松散耦合,干净,易于使用。除了一个问题之外,DI似乎几乎是一种解决方案:跨领域和可选的依赖导致构造或财产污染。所以我来为我自己的解决方案和我想知道你怎么看它。依赖注入+环境上下文+服务定位器
Mark Seemann(DI书的作者,着名的“SL is anti-patter”声明)在他的书中提到了一种叫做Ambient Context的模式。虽然他说他不太喜欢它,但这种模式仍然很有趣:它就像旧的单身人士,除了它是作用域并提供默认值的,所以我们不必检查null。它有一个缺陷 - 它没有,它不知道它的范围和如何处理它自己。
那么,为什么不在这里应用服务定位器?它可以解决范围和处理环境上下文对象的问题。在你说它是反模式之前:这是你隐藏合约的时候。但在我们的情况下,我们隐藏可选合约,所以它不是那么糟糕IMO。
这里是一些代码来说明我的意思:
public interface ILogger
{
void Log(String text);
}
public interface ISomeRepository
{
// skipped
}
public class NullLogger : ILogger
{
#region ILogger Members
public void Log(string text)
{
// do nothing
}
#endregion
}
public class LoggerContext
{
public static ILogger Current
{
get
{
if(ServiceLocator.Current == null)
{
return new NullLogger();
}
var instance = ServiceLocator.Current.GetInstance<ILogger>();
if (instance == null)
{
instance = new NullLogger();
}
return instance;
}
}
}
public class SomeService(ISomeRepository repository)
{
public void DoSomething()
{
LoggerContext.Current.Log("Log something");
}
}
编辑:我知道,不问具体问题与堆栈溢出设计冲突去。因此,我将标记为最好的描述为什么这个设计不好或更好的解决方案(或者可能是另外的?)的答案。但是,不建议AOP,这很好,但是当你真的想在你的代码中做些什么的时候,这不是一个解决方案。
编辑2:我添加了一个检查ServiceLocator.Current为空。这就是我想要我的代码所做的:在未配置SL时使用默认设置。
我从你的问题中遗漏了一个例子,你清楚地表明你需要使用'LoggerContext.Current'而不是在代码中注入一个'ILogger'。根据我的经验,如果您需要在代码中注入许多'ILogger'依赖项,您要么记录太多(而不是抛出异常),或者您没有遵守SRP(实际上您需要AOP)。看看这个答案:http://stackoverflow.com/questions/9892137/windsor-pulling-transient-objects-from-the-container。 – Steven