使用dependency injection框架时的抽象工厂
我想知道如何在使用DI框架时正确使用抽象工厂,并且该工厂中的一个参数是应该由DI框架处理的依赖项。
我不确定是否让我的抽象工厂完全省略参数然后使用我的DI容器连接它或者是否应该将依赖项传递给对象。
例如,我有一个TcpServer,它使用Session.Factory来创建套接字。 Session对象实际上在其构造函数中使用了Processor。 我应该将处理器传递给TcpServer然后将它传递给Session.Factory还是让我的DI容器进行接线?
如果我要让DI容器进行接线,它将如下所示:
class Session : ISession { public delegate ISession Factory(string name); ... public Session(string name, Processor processor) { ... } } class TcpServer : ITcpServer { private readonly Session.Factory _sessionFactory; public TcpServer(Session.Factory sessionFactory) { this._sessionFactory = socketFactory; } ... public void OnConnectionReceived() { ... var session= _sessionFactory(ip.LocalEndPoint()); ... } }
然后使用像Ninject这样的DI容器,我可以在配置容器时执行此操作:
Bind().ToMethod(c => { var processor = Kernel.Get(); return (name) => new Session(name, processor); }).InSingletonScope();
这种方法的主要问题在于它假设创建Session.Factory的人知道处理器。 在我的情况下,由于我使用的是DI容器,这实际上非常方便,但是让工厂拥有自己的依赖项似乎很奇怪。 我总是想象一个工厂真的没有任何成员。
如果我要通过依赖
class Session : ISession { public delegate ISession Factory(string name, Processor processor); ... public Session(string name, Processor processor) { ... } } class TcpServer : ITcpServer { private readonly Session.Factory _sessionFactory; private readonly Processor _processor; public TcpServer(Session.Factory sessionFactory, Processor processor) { this._processor = processor; } ... public void OnConnectionReceived() { ... var session = _sessionFactory(ip.LocalEndPoint(), _processor); ... } }
第二种方法有两个问题:
- TcpServer实际上对处理器没有任何作用。 它只是传递它。 这似乎是穷人的DI在工作中差不多。
- 在这段代码背后的真实程序中,Processor实际上有一个对TcpServer的引用。 因此,当使用这种方法时,我得到一个循环引用。 当我使用第一个场景将其分开时,那不是问题。
您认为最好的方法是什么? 我也对新想法持开放态度。
谢谢!
许多容器以一种或另一种方式支持工厂,这是你应该去的方式。
举例来说,像这样定义一个ISessionFactory接口
public interface ISessionFactory { ISession CreateSession(string name); }
对于Ninject 2.3,请参阅https://github.com/ninject/ninject.extensions.factory并让它由Ninject实现
Bind().AsFactory();
对于2.2自己实施
public class SessionFactory : ISessionFactory { private IKernel kernel; public SessionFactory(IKernel kernel) { this.kernel = kernel; } public ISession CreateSession(string name) { return this.kernel.Get(new ConstructorArgument("name", name)); } }
我用于抽象工厂模式的模式与您的模式略有不同。 我在通用单例上使用类似setter注入的东西,但在更直观的界面中包装可配置委托“property”。
我不希望单独注册每个实现,所以我更喜欢使用一些可以在应用程序启动时测试的约定。 我不确定用于自动调整自定义约定的Ninject语法,但逻辑将归结为扫描相关程序集的引用类型T,它具有AbstractFactory
类型的静态只读字段,然后调用Configure(Func
使用reflection在静态成员上。
下面是一个通用抽象工厂单例的示例以及如何在Session
上声明它。
public class Session { public static readonly AbstractFactory Factory = AbstractFactory .GetInstance(); } public sealed class AbstractFactory where T: class{ static AbstractFactory(){ Bolt = new object(); } private static readonly object Bolt; private static AbstractFactory Instance; public static AbstractFactory GetInstance(){ if(Instance == null){ lock(Bolt){ if(Instance == null) Instance = new AbstractFactory (); } } return Instance; } private AbstractFactory(){} private Func m_FactoryMethod; public void Configure(Func factoryMethod){ m_FactoryMethod = factoryMethod; } public T Create() { if(m_FactoryMethod == null) { throw new NotImplementedException(); } return m_FactoryMethod.Invoke(); } }
更新
如果需要将参数传递给工厂方法,则可以更改类,例如:
public sealed class AbstractFactory where T: class{ static AbstractFactory(){ Bolt = new object(); } private static readonly object Bolt; private static AbstractFactory Instance; public static AbstractFactory GetInstance(){ if(Instance == null){ lock(Bolt){ if(Instance == null) Instance = new AbstractFactory(); } } return Instance; } private AbstractFactory(){} private Func m_FactoryMethod; public void Configure(Func factoryMethod){ m_FactoryMethod = factoryMethod; } public T Create(TDataContract data) { if(m_FactoryMethod == null) { throw new NotImplementedException(); } return m_FactoryMethod.Invoke(data); } }
您的SessionData
, Session
和TcpServer
可能看起来像
public class SessionData{ public DateTime Start { get; set; } public string IpAddress { get; set; } } public class Session { public static readonly AbstractFactory Factory = AbstractFactory.GetInstance(); private readonly string _ip; private readonly DateTime _start; public Session(SessionData data) { _ip = data.IpAddress; _start = DateTime.Now; } public event EventHandler RequestAdded; } public class RequestReceivedEventArgs: EventArgs { public SessionRequest Request { get; set; } } public class TcpServer : ITcpServer { private readonly Processor _processor; public TcpServer(Processor processor) { this._processor = processor; } public void OnConnectionReceived() { var sessionData = new SessionData { IpAddress = ip.LocalEndPoint(), Start = DateTime.Now }; var session = Session.Factory.Create(sessionData); //...do other stuff } public void ServeResponse(SessionRequest request){ _processor.Process(request); } }
配置DI容器时,可以设置工厂,例如:
上述就是C#学习教程:使用dependency injection框架时的抽象工厂分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
Session.Factory.Configure(sessionData => { // instead of injecting the processor into the Session, configure events // that allow the TcpServer to process the data. // (After all, it is more logical for a servers to serve a request than // it is for a Session to do the Processing. Session's tend to store data // and state, not invoke processes session.RequestAdded += (sender,e) => { Kernel.Get.ServeResponse(e.Request); }; });
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/1029582.html