【发布时间】:2012-05-21 10:01:44
【问题描述】:
最近我阅读了很多关于应用程序设计模式的内容:关于 DI、SL 反模式、AOP 等等。原因——我想在设计上做出妥协:松散耦合、干净且易于使用。 DI 似乎几乎是一种解决方案,除了一个问题:导致构造函数或属性污染的横切和可选依赖项。因此,我为此提出了自己的解决方案,我想知道您对此有何看法。
Mark Seemann(DI 书籍的作者和著名的“SL 是反模式”声明)在他的书中提到了一种称为 Ambient Context 的模式。尽管他说他不太喜欢它,但这种模式仍然很有趣:它就像旧的好单例,只是它是作用域的并提供默认值,因此我们不必检查 null。它有一个缺陷——它没有而且它不知道它的范围以及如何处理自己。
那么,为什么不在这里应用服务定位器呢?它可以解决环境上下文对象的作用域和处置问题。在你说它是反模式之前:这是你隐藏合同的时候。但在我们的例子中,我们隐藏了 OPTIONAL 合同,所以 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)。看看这个答案:stackoverflow.com/questions/9892137/….
标签: dependency-injection service-locator cross-cutting-concerns