Inspired from Mark Seemann's post: Pattern Recognition: Abstract Factory or Service Locator?
I wish to write an abstract factory like so:
public interface IAbstractFactory {
T Create<T>();
}
Then, binding it using Ninject like so:
IKernel kernel = new StandardKernel();
kernel.Bind<IAbstractFactory>().ToFactory();
Then, one may use it as follows:
public class CustomerServiceIndicatorsModel {
public CustomerServiceIndicatorsModel(IAbstractFactory factory) {
this.emailIndicatorA = factory.Create<EmailIndicatorA>();
this.emailIndicatorB = factory.Create<EmailIndicatorB>();
this.emailIndicatorC = factory.Create<EmailIndicatorC>();
}
}
Again, I'm not referencing the Ninject's kernel anywhere, and this works. The kernel is only refered to in the Global.asax.cs
file for the bindings.
Can it be considered as an acceptable implementation of the abstract factory pattern?
I have a hard time trying to get the jist of this pattern. I understand the Factory
pattern clearly as being a delegated class which creates instances of a given type.
public interface IEmailIndicatorAFactory {
EmailIndicatorA Create();
}
Then, when I bind it ToFactory()
using Ninject, it shall create instances of EmailIndicatorA
.
How to bind IAbstractFactory<T>
using Ninject, since each type:
IAbstractFactory<EmailIndicatorA>
IAbstractFactory<EmailIndicatorB>
IAbstractFactory<EmailIndicatorC>
is considered a completely concrete type. And I can't find a way to bind it using Ninject
.
And I don't see any benefit of writing such an interface if in return I have to write:
public interface EmailIndicatorAFactory : IAbstractFactory<EmailIndicatorA> { }
public interface EmailIndicatorBFactory : IAbstractFactory<EmailIndicatorB> { }
public interface EmailIndicatorCFactory : IAbstractFactory<EmailIndicatorC> { }
After a comment by @PrestonGuillot, I fell in the latter implementing the ServiceLocator
instead of the AbstractFactory
as I'm using a generic Create<T>()
method, and the Abstract Factory
uses a non-generic Create()
method.
Thanks for pointing it out, @PrestonGuillot! =)
Perhaps I am overcomplicating things here... So here's my model:
EmailIndicator
public abstract EmailIndicator {
int EmailCount { get; set; }
DateTime OldestDateTimeReceived { get; set; }
}
EmailIndicatorA
public class EmailIndicatorA : EmailIndicator { }
EmailIndicatorB
public class EmailIndicatorB : EmailIndicator { }
EmailIndicatorC
public class EmailIndicatorC : EmailIndicator { }
IEmailIndicatorRepository
public interface IEmailIndicatorRepository<T> where T : EmailIndicator {
T GetIndicator();
}
public class EmailIndicatorARepository : IEmailIndicatorRepository<EmailIndicatorA> {
public EmailIndicatorARepository(IExchangeService service
, IExchangeConfiguration configuration
, INetworkCredentialFactory credentialFactory) {
exchangeService = service;
exchangeService.Url = configuration.ExchangeUri;
exchangeService = credentialFactory.Create(configuration.Login, configuration.Password);
}
EmailIndicatorA GetIndicator() {
// Code to query Exchange through its Web services here...
}
}
And two other repository like this one exist, since I have to query three different Exchange servers in my application.
I believe there is room for using the Abstract Factory
, and because I am still learning the pattern, I just don't get how to implement it yet in my situation.
If not for the indicators themselves, perhaps I can finally get a grasp on the Abstract Factory
with my reposptories.
As far as my understanding goes, here's what I would try as a first step toward a solution:
IRepositoryFactory
public interface IRepositoryFactory<T> where T : class, new() {
T Create();
}
IEmailIndicatorARepositoryFactory
public interface IEmailIndicatorARepositoryFactory
: IRepositoryFactory<EmailIndicatorARepository> {
EmailIndicatorARepository CreateEmailIndicatorARepository();
}
IEmailIndicatorBRepositoryFactory
public interface IEmailIndicatorBRepositoryFactory
: IRepositoryFactory<EmailIndicatorBRepository> {
EmailIndicatorBRepository CreateEmailIndicatorBRepository();
}
And the Abstract Factory ?
public abstract IEmailIndicatorRepositoryFactory
: IEmailIndicatorARepositoryFactory
, IEmailIndicatorBRepositoryFactory
, IEmailIndicatorCRepositoryFactory {
EmailIndicatorARepository CreateEmailIndicatorARepository() { // create instance here... }
EmailIndicatorBRepository CreateEmailIndicatorBRepository() { // create instance here... }
EmailIndicatorCRepository CreateEmailIndicatorCRepository() { // create instance here... }
}
Is this a better approach?
I'm kind of lost and confused here.
I'm finding the diagrams of the Wikipedia article quite enlightening.
I think the name "Abstract Factory" is a bit misleading in the .net / c# world. You only need an
abstract class
in case the language doesn't support interfaces or you want to share implementation (but remember favor composition over inheritance).Since you mentioned Mark Seeman i'd like to distill my interpretation of a few of his posts regarding IoC and Factory:
So given your example this would be:
with three implementations, one for
EmailIndicatorA
,EmailIndicatorB
andEmailIndicatorC
each. Now to make the argument matter, theEmailIndicator
needs a dependency specific toEmailIndicatorA
, (or B, C). Let's say it requiresIServiceA
:Now there should be a corresponding factory which receives the dependencies of
EmailIndicatorA
:That's it. If
EmailIndicatorA
had additional dependencies, they should be injected intoEmailIndicatorAFactory
, too.Now the benefit of doing all of this code is fail-fast. All the other issues can be addressed by correct use of
.ToFactory()
bindings and interfaces which aren't too generic but specific instead (well basically the same ones as with the abstract factory above!).I think you should carefully weigh the pro's and con's.
Mark also said that he's using IoC containers seldomly anymore. Instead he most often prefers poor man's di. See this post.
I think Mark is very good at pointing out pro's and con's and reading his posts is very educational. I don't agree with all his conclusions, but TBH I would love to work with him on a project for a while (not just a few weeks, longer) and then see whether i agree or not.
Having said that i would like to offer you an alternative way to handle the use cases for the abstract factory pattern. Since i've already posted it on SO before there's nothing left to do but to link it :)
As a last note, i don't know of any IoC container which features
Func<>
or interface factories like Ninject's.ToFactory()
which early instantiate the dependencies. It is only done once you execute theFunc<>
or call theIFooFactory.CreateFoo()
method. So the issue of fail-fast has not yet been addressed by auto-generated factories. However, what has been done is that some containers have verification methods which verify that types can be instantiated and that there are no Captive Dependencies. For example Simple Injector