Is this a right or viable implementation of the Abstract Factory pattern?

354 views Asked by At

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.

1

There are 1 answers

1
BatteryBackupUnit On BEST ANSWER

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:

  • don't use service locator
  • create a composition root. Ideally it should instantiate all objects in one go at the beginning.
    • as such you should design your objects to be stateless and only process data - whenever possible (separation of data and processing logic). That means you only have to instantiate more or less data classes / data structs, which don't have any dependencies. All the objects with dependencies are created in one go upon application start up.
  • late creation is not failing fast
    • if you use late creation, whether you call it service locator or factory, this decreases testability, since issues will not be visible upon application startup but rather only when you're using/creating the object at a later time.
    • to remedy this somewhat, create all dependencies of the object to be created by the factory already @composition root. Only late-create the actual object.
    • this is done using the abstract factory pattern.

So given your example this would be:

public interface IEmailIndicatorFactory
{
    IEmailIndicator Create();
}

with three implementations, one for EmailIndicatorA, EmailIndicatorB and EmailIndicatorC each. Now to make the argument matter, the EmailIndicator needs a dependency specific to EmailIndicatorA, (or B, C). Let's say it requires IServiceA:

internal class EmailIndicatorA : IEmailIndicator
{
    private readonly IServiceA serviceA;

    public EmailIndicatorA(IServiceA serviceA)
    {
        this.serviceA = serviceA;
    }

    (...)
}

Now there should be a corresponding factory which receives the dependencies of EmailIndicatorA:

internal class EmailIndicatorAFactory : IEmailIndicatorFactory
{
    private readonly IServiceA serviceA;

    public EmailIndicatorAFactory(IServiceA serviceA)
    {
        this.serviceA = serviceA;
    }

    public IEmailIndicator Create()
    {
        return new EmailIndicatorA(this.serviceA);
    }
}

That's it. If EmailIndicatorA had additional dependencies, they should be injected into EmailIndicatorAFactory, 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 the Func<> or call the IFooFactory.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