Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I apply dependency injection to an abstract factory

I've just finished Mark Seemann's book Dependency Injection in .NET and I'm now trying to refactor some legacy code. (I am not, at this stage, relying on any particular DI container, rather just trying to move all the dependencies to one place).

I'm looking at the following factory class which determines the ArchiveType by reading the first few bytes of the archive with archiveReader.GetArchiveType() and then returns an instance of an ArchiveRestorer based on the ArchiveType enum.

public class ArchiveRestorerFactory : IArchiveRestorerFactory
{
    public ArchiveRestorer Create(ArchiveReader archiveReader)
    {
        ArchiveType type = archiveReader.GetArchiveType();
        switch (type)
        {
            case ArchiveType.CurrentData:
                return new CurrentDataArchiveRestorer(archiveReader);
                break;
            case ArchiveType.HistoricalData:
                return new HistoricalDataArchiveRestorer(archiveReader);
                break;
            case ArchiveType.AuditTrail:
                return new AuditTrailArchiveRestorer(archiveReader);
                break;
            default:
                throw new Exception("ArchiveRestorerFactory error: Unknown value for ArchiveType.");
        }
    }
}

How do I refactor this so that the class does not depend on the concrete types CurrentDataArchiveRestorer, HistoricalDataArchiveRestorer and AuditTrailArchiveRestorer?

Should I move the three concrete restorers into the factory's constructor?

public ArchiveRestorer Create(ArchiveReader archiveReader, 
    ArchiveRestorer currentDataArchiveRestorer, 
    ArchiveRestorer historicalDataArchiveRestorer, 
    ArchiveRestorer auditTrailDataArchiveRestorer)
{
    // guard clauses...
    // assign to readonly fields
}

That seems to be the approach suggested here, but then it will instantiate all three restorers when only one is needed? What if I had 20 different possible concrete implementations instead?

I feel like I should be implementing a concrete factory for each type of restorer and returning that instead but then I would just be replacing one new with another.

What is the best way to refactor this?

like image 207
shamp00 Avatar asked Feb 02 '12 17:02

shamp00


People also ask

Can we use dependency injection in abstract class?

Any concrete class inheriting the abstract class should be instantiable with a constructor (if not abstract itself of course). But use of constructor is prohibited by Spring because any class that we instantiate this way cannot be taken in charge by Spring's automated dependency injection.

How do we implement dependency injection?

Dependency Injection is done by supplying the DEPENDENCY through the class's constructor when creating the instance of that class. The injected component can be used anywhere within the class. Recommended to use when the injected dependency, you are using across the class methods.

Is dependency injection an abstraction?

Dependency Injection (DI) is a technique that helps us achieve loose coupling between objects and their collaborators. In this post, we will use constructor based dependency injection, however, we are not going to use any DI container for now.


1 Answers

The way I'd do this, given the code you've already got, would be to create a factory for each of these objects which has a Create() method.

I'd have an interface for these factories also and have them inherit from a general factory interface.

You can then use the interfaces as a point for injection into your constructor.

Which would be called similar to this:

case ArchiveType.CurrentData:
                return _currentDateArchiveRestorerFactory.Create(archiveReader);
                break;

Alternatively, it might be better to have a single factory that creates an instance of a given type. Since all of these objects are restorers you could just create the instance based on the enum rather than a switch.

_restorerFactory.Create(ArchiveType.CurrentData);
like image 172
Jamie Dixon Avatar answered Sep 29 '22 06:09

Jamie Dixon