Any place where you need a run-time value to construct a particular dependency, Abstract Factory is the solution.
My question is: Why do many sources favor FactoryInterface over FactoryDelegate to implement this pattern? What are the pros and contras for both solutions?
Here is an example to understand what I mean:
If you have a Service
that needs a Repository
with a certain Context
, then the Service
constructor needs a factory to create or access its repository.
The common solution for this is to create a RepositoryFactoryInterface like this:
public IRepositoryFactory {
IRepository Create(ContextInformation context);
}
public class MyService {
private IRepositoryFactory repositoryFactory;
public MyService(IRepositoryFactory repositoryFactory)
{
this.repositoryFactory = repositoryFactory:
}
public void DoSomeService()
{
ContextInformation context = ....;
IRepository repository = this.repositoryFactory.Create(context);
repository.Load(...);
...
repository.Save(...);
}
}
You also need to implement IRepositoryFactory
interface some way...
public MyEf4RepositoryFactory : IRepositoryFactory
{
IRepository Create(ContextInformation context)
{
return new MyEf4Repository(context);
}
}
... and use it in the application:
public void main()
{
IRepositoryFactory repoFactory = new MyEf4RepositoryFactory();
IService service = new MyService(repoFactory);
service.DoSomeService();
}
----- End of mainstream solution ------
Instead of the RepositoryFactoryInterface, you can do the same with a FactoryDelegate that requires less coding like this...
public class MyService {
private Func<ContextInformation, IRepository> repositoryFactory;
public MyService(Func<ContextInformation, IRepository> repositoryFactory)
{
this.repositoryFactory = repositoryFactory:
}
public void DoSomeService()
{
ContextInformation context = ....;
IRepository repository = this.repositoryFactory(context);
repository.Load(...);
...
repository.Save(...);
}
}
... and use it in the application:
public void main()
{
IService service = new MyService(context => new MyEf4Repository(context));
service.DoSomeService();
}
In my opinion, the FactoryDelegate context => new MyEf4Repository(context)
is much more compact than
declaring and implementing an interface IRepositoryFactory
and MyEf4RepositoryFactory
.
There must be a reason for this and I want to know why.
Here is one example source that uses the interface approach: answer to is-there-a-pattern-for-initializing-objects-created-via-a-di-container
[Update] 15 months after asking this question and having more experience with the Java universe, I changed my mind: Now I prefer interfaces over delegates. But I cannot say why. It is just a feeling. Maybe because I am more used to it?
Personally, I have always used the mainstream solution, simply because I didn't think of using a delegate.
After I thought of it, I faced the problem of separation of concerns. I'm using Ninject, and I didn't want my binding module to look like this (imagine the repositoy having some dependencies of itself):
class IoCModule : NinjectModule
{
public override Load()
{
Bind<Func<Context, IRepository>>()
.ToConstant( context => new MyEf4Repository(context, Kernel.Get<IRepositoryDependency1>, Kernel.Get<IRepositoryDependency2>) );
}
}
That isn't readable at all. So I still used fully typed out abstract factories for Separation of Concern and readability.
Now I use the FuncModule described in this question (a la AutoFac). So I can do this:
class IoCModule : NinjectModule
{
public override Load()
{
Bind<IRepository>().To<MyEf4Repository>();
Bind<IRepositoryDependency1>().To<...>();
Bind<IRepositoryDependency2>().To<...>();
}
}
and let ninject figure the dependencies out for me. As you can see, it's both more readable than using the method described above, and having to bind the factories for each dependency. This is the way I made the transition from the mainstream solution to the delegate solution.
So to answer your question. The reason I used the mainstream solution was because I didn't know how to do it another way at first (this is partly caused by most blogs fully typing out the abstract factories, can you see the circle?).