Dependency injection 依赖注入&x2B;环境上下文+;服务定位器
最近我读了很多关于应用程序设计模式的东西:关于DI、SL反模式、AOP等等。原因是——我想达成一个设计折衷方案:松散耦合、干净且易于使用。DI看起来几乎像是一个解决方案,除了一个问题:横切和可选依赖性导致构造函数或属性污染。因此,我提出了自己的解决方案,我想知道您对此有何看法 Mark Seemann(DI书的作者,著名的“SL是反模式的”陈述)在他的书中提到了一种称为环境语境的模式。尽管他说他不太喜欢它,但这个模式仍然很有趣:它就像旧的优秀的singleton,只是它的作用域是有限的,并且提供了默认值,所以我们不必检查null。它有一个缺陷——它没有,也不知道它的范围和如何处理自己 那么,为什么不在这里应用服务定位器呢?它可以解决环境上下文对象的作用域和处理问题。在你说它是反模式之前:它是当你隐藏合同时。但在我们的例子中,我们隐藏了可选合同,所以在我看来,这并不坏 这里有一些代码来说明我的意思:Dependency injection 依赖注入&x2B;环境上下文+;服务定位器,dependency-injection,service-locator,cross-cutting-concerns,Dependency Injection,Service Locator,Cross Cutting Concerns,最近我读了很多关于应用程序设计模式的东西:关于DI、SL反模式、AOP等等。原因是——我想达成一个设计折衷方案:松散耦合、干净且易于使用。DI看起来几乎像是一个解决方案,除了一个问题:横切和可选依赖性导致构造函数或属性污染。因此,我提出了自己的解决方案,我想知道您对此有何看法 Mark Seemann(DI书的作者,著名的“SL是反模式的”陈述)在他的书中提到了一种称为环境语境的模式。尽管他说他不太喜欢它,但这个模式仍然很有趣:它就像旧的优秀的singleton,只是它的作用域是有限的,并且提供
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");
}
}
公共接口ILogger
{
无效日志(字符串文本);
}
公共接口异构存储
{
//跳过
}
公共类NullLogger:ILogger
{
#区域ILogger成员
公共作废日志(字符串文本)
{
//无所事事
}
#端区
}
公共类LoggerContext
{
公共静态ILogger电流
{
得到
{
if(ServiceLocator.Current==null)
{
返回新的NullLogger();
}
var instance=ServiceLocator.Current.GetInstance();
if(实例==null)
{
实例=新的NullLogger();
}
返回实例;
}
}
}
公共类服务(异构存储库)
{
公共无效剂量测定法()
{
LoggerContext.Current.Log(“记录某物”);
}
}
编辑:我意识到不问具体问题与堆栈溢出设计相冲突。因此,我会在一篇文章中给出一个最好的答案,描述为什么这种设计不好或更好,并给出更好的解决方案(或者添加?)。但不要建议使用AOP,这很好,但当您真的想在代码中执行某些操作时,它不是一个解决方案
编辑2:我为ServiceLocator添加了一个检查。当前为空。这就是我的代码要做的:在没有配置SL的情况下使用默认设置。您所建议的环境上下文的一个问题是,它使测试更加困难。出于以下几个原因:
ILogger
ILogger
实例注入到需要它的服务中来解决,而不是使用环境上下文
如果系统中有许多类依赖于ILogger
抽象,那么您应该认真地问问自己
还请注意。您可以使用手工制作的装饰器或某种拦截(例如,或)添加横切关注点
因此,您根本不必将
ILogger
注入核心业务类。您的问题中缺少的是一个示例,您清楚地表明需要使用LoggerContext.Current
而不是在代码中注入ILogger
。根据我的经验,如果您需要在整个代码中注入许多ILogger
依赖项,那么您要么记录得太多(而不是抛出异常),要么没有遵守SRP(实际上您确实需要AOP)。请看以下答案:.1。史蒂文,我忘了检查ServiceLocator。当前为空,谢谢你指出这一点。通过此检查,测试不会被迫初始化SL.2。为什么我首先要测试像ILogger这样的东西?但如果我愿意,这仍然是可行的。3.我同意-如果你想测试它,这是一个问题。但再一次,这是可行的。最后,更重要的是:轻松编写真正的代码还是轻松编写测试。有很多研究证明,如果不能够测试代码,就无法编写高质量的代码。因此,能够轻松编写测试对于编写高质量的应用程序至关重要。@DmitryGlobets:让我来扭转这一局面。为什么不想在类中测试ILogger的用法?既然您已经编写了这段代码,那么这一定是有价值的业务逻辑,您应该想知道这段代码是否正确。如果这段代码不是很有价值,你为什么不先写呢?也许这一行是一个横切关注点(AOP),而不是重要的业务逻辑。在这种情况下,您不应该使您的业务逻辑复杂化,您应该将此逻辑提取到装饰程序或某种类型的程序中。关于第3点。看起来MSTest默认以串行方式运行测试()是的,我到处都读到了相同的建议,但我觉得它不对。有时,日志应该写入某个“if”分支中的方法内部。拦截并不能解决这个问题。ILogger只是一个例子,但也可能有其他接口具有读取某些值的方法。@DmitryGlobets:如果您认为日志记录是类的一个重要方面,那么请明确这一点,并使用构造函数注入将其注入。如果它用于跟踪输入值和日志异常(我处理日志和