Constructor Injection Alternatives (Castle Windsor)
我喜欢依赖注入的构造函数注入。它强制类型明确声明关注点,并帮助实现可测试性。
我喜欢构造函数注入,在大多数地方…
作为一个我不喜欢的例子记录。如果我有一个基类,许多其他类都从这个基类继承,我希望所有这些类都使用我的i logger(或其他类)的一个实例,并且我不希望使用静态工厂(logger.instance)…我不希望在每个接受ilogger的子类上声明构造函数。
所以,我可以让我的基类将记录器声明为一个属性,并以这种方式注入它
1 2 3 4 | public class MyBaseClass { public ILogger Logger { get; set; } } |
但…
那么……我还有别的选择吗?(我在使用温莎城堡)。
我打算做一个界面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public interface IInitializable<T> { void Initialize(T instance); } public class MyBaseClass : IInitializable<ILogger>, ...could have other IInitializables too... { protected ILogger Logger { get; private set; } public void Initialize(ILogger instance) { Logger = instance; } } |
然后在我的容器上有一个在类型构造时自动调用
但在我走那条路之前,我想知道其他人的想法是什么…
你太复杂了。注入ilogger的推荐和文档化模式是将
我将从这里的文档中复制样本,以便于参考:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | using Castle.Core.Logging; public class CustomerService { private ILogger logger = NullLogger.Instance; public CustomerService() { } public ILogger Logger { get { return logger; } set { logger = value; } } // ... } |
编辑:看起来问题实际上是关于根据上下文使用不同的记录器实现(这与原始问题几乎没有关系)。如果是这样,请使用服务重写或处理程序选择器。
在您的情况下,我将使用属性注入。
属性注入可以切换为强制,如下所述:http://www.mail-archive.com/[email protected]/msg08163.html
如果您的基类本身不依赖于
否则,您可以创建一个能够创建
1 2 3 4 | public interface IMyBaseClassFactory { MyBaseClass CreateNew<TMyBaseClass>() where TMyBaseClass : MyBaseClass; } |
现在,您可以创建一个注册
1 2 3 4 5 6 7 8 9 10 11 12 13 | public MyBaseClassFactoryImpl : IMyBaseClassFactory { public MyBaseClass CreateNew<TMyBaseClass>() { // Call your IoC container to get a descendant. var instance = ServiceLocator.GetInstance<TMyBaseClass>(); // Register missing dependencies instance.Logger = ServiceLocator.GetInstance<ILogger>(); return instance; } } |
大多数IOC容器允许您用属性来装饰可注入属性。但是,使用工厂的好处是,您的应用程序将完全不了解使用的IOC框架。作为缺点,还有更多的工作要做(创建一个工厂,注入该工厂而不是实例本身,并调用工厂来创建一个新的实例)。
定义可注入属性时,需要使其读/写。当然,您不希望任何人在事后意外重置该属性。如果没有构造函数注入,很难通过编译时支持实现这一点。但是,运行时检查很容易:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | private ILogger logger; public ILogger Logger { get { return this.logger; } set { if (this.logger != null) { throw new InvalidOperationException("Logger has already been set."); } this.logger = value; } } |
我希望这有帮助。