最近我读了很多关于应用程序设计模式的东西:关于DI,SL反模式,AOP等等。原因 - 我想要达成设计妥协:松散耦合,干净且易于使用。除了一个问题外,DI似乎几乎就像一个解决方案:交叉和可选的依赖导致构造函数或属性污染。所以我为此提出了自己的解决方案,我想知道你怎么看。
Mark Seemann(DI书的作者和着名的“SL is anti patter”声明)在他的书中提到了一种叫做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为null。这就是我的代码要做的事情:在未配置SL时使用默认设置。
答案 0 :(得分:3)
您提出的环境上下文问题在于它使测试更加困难。原因有两个:
ILogger
注册。所有这些问题都可以通过简单地将ILogger
实例注入需要它的服务来解决,而不是使用环境上下文。
如果您系统中的许多课程依赖于ILogger
抽象,那么您应该认真地问自己whether you're logging too much。
答案 1 :(得分:3)
您可以使用手工制作的装饰器或某种拦截方式添加横切关注点(例如Castle DynamicProxy或Unity's interception extension)。
因此,您根本不必将ILogger
注入核心业务类。