I'm wondering how to properly use abstract factories when using a DI framework and one of the parameters in that factory is a dependency that should be handled by the DI framework.
I am not sure whether to make my abstract factory omit the parameter completely then use my DI container to wire it up or whether I should pass the dependency to the object.
For example, I have a TcpServer and it uses a Session.Factory to create sockets. The Session object actually takes a Processor in its constructor. Should I pass the Processor to the TcpServer then have it pass it onto the Session.Factory or have my DI container do the wiring?
If I were to have the DI container do the wiring it would look like this:
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());
...
}
}
Then using a DI container like Ninject I'd be able to do this when configuring the container:
Bind<Session.Factory>().ToMethod(c =>
{
var processor = Kernel.Get<Processor>();
return (name) => new Session(name, processor);
}).InSingletonScope();
My main issue with this approach is that it assumes whoever creates the Session.Factory knows about the processor. In my case, since I am using a DI container, this is actually very convenient but it seems weird to have a factory have its own dependencies. I always imagined a factory not really ever having any members.
If I were to pass the dependency through
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);
...
}
}
I have two issues with the second approach:
- The TcpServer doesn't actually do anything with the Processor. It just passes it along. Seems like this is poor man's DI at work almost.
- In the real program behind this code, the Processor actually has a reference to the TcpServer. Therefore when using this approach, I get a circular reference. When I break it apart by using the first scenario then it's not an issue.
What do you think is the best approach? I am open to new ideas as well.
Thanks!
Many containers support factories in one or another way and this is the way you should go.
E.g. Taking your example define a ISessionFactory interface like this
For Ninject 2.3 see https://github.com/ninject/ninject.extensions.factory and let it be implemented by Ninject
For 2.2 do the implementation yourself
The pattern I use for an abstract factory pattern is a little different from yours. I use something like setter injection on a generic singleton, but wrap the configurable delegate "property" in a more intuitive interface.
I would prefer not to have to register each implementation individually, so I would prefer to use some convention that can be tested at application start up. I'm not sure about the Ninject syntax for autoregistering custom conventions, but the logic would come down to scanning the relevant assemblies for reference types, T, that have static readonly fields of type
AbstractFactory<T>
, then callingConfigure(Func<T>)
on that static member using reflection.An example of the generic abstract factory singleton and how it would be declared on a
Session
is below.Update
If you need to pass parameters into your factory method, then you can alter the class such as:
Your
SessionData
,Session
andTcpServer
might look likeWhen configuring your DI container, you can set up the factory such as: