Factory Factory pattern: easier than using a container

Spread the love

Here’s a simple example of a class that creates file transfers using different protocols, which can be combined into a big queue later:

public class TransferFactory : ITransferFactory{    public Transfer CreateFtpTransfer(string path)    {        return new Transfer(path, ftpStreamFactory);    }        public Transfer CreateHttpTransfer(string path)    {        return new Transfer(path, httpStreamFactory);    }    public Transfer CreateSmbTransfer(string path)    {        return new Transfer(path, smbStreamFactory);    }    public Transfer CreateSftpTransfer(string path)    {        return new Transfer(path, sftpStreamFactory);    }}

It’s based loosely on something I wrote last week at work, and you can see some pretty classic examples of the Strategy and Abstract Factory patterns here. But where do all the stream factories come from? You could inject them all separately:

public class TransferFactory : ITransferFactory{    public TransferFactory(IStreamFactory ftpStreamFactory,        IStreamFactory httpStreamFactory,        IStreamFactory smbStreamFactory,        IStreamFactory sftpStreamFactory)    {        this.ftpStreamFactory = ftpStreamFactory;        this.httpStreamFactory = httpStreamFactory;        this.smbStreamFactory = smbStreamFactory;        this.sftpStreamFactory = sftpStreamFactory;    }    ...}

But classes like this are horrible to register in an IoC container. Named instances, kilometers of identical positional parameters, and nothing preventing you putting them in the wrong order by accident… messy.

A tidier approach would be to employ the factory factory pattern, where instead of injecting all the factories separately, you just provide one that can create them all:

public class TransferFactory : ITransferFactory{    public TransferFactory(IStreamFactoryFactory streamFactories)    {        this.streamFactories = streamFactories;    }    public Transfer CreateFtpTransfer(string path)    {        return new Transfer(path, streamFactories.CreateFtpStreamFactory());    }        public Transfer CreateHttpTransfer(string path)    {        return new Transfer(path, streamFactories.CreateHttpStreamFactory());    }    ...}

Now some would argue that having factories to create factories is a sure sign of being an architect astronaut, and noone should ever need such a thing. But in examples like this I think they are entirely appropriate, and make your code that much easier to work with.