benjamin.cohen-solal
benjamin.cohen-solal

Reputation: 481

Handle dependency injection with factory method DP

We have to implement a factory able to create several complex objects. How should we handle it with dependency injection ?

I already read many topics about it in stackoverflow (and elsewhere), particularly the ones of Mark Seemann but can't take any decision so need your opinion.

For example:

<?php
class EventFactory
{
    public function createEvent($type)
    {
        switch ($type) {
            case 'upload':
                return new UploadEvent(new FtpUploader(), new Mailer());
            case 'download':
                return new DownloadEvent(new FtpDownloader(), new Mailer());
            case 'save':
                return new SaveEvent(new EventDbModel());
            case 'load':
                return new LoadEvent(new EventDbModel());
            case 'notify':
                return new NotifyEvent(new HttpRequester());
        }
    }
}

I found some solutions but don't know which one to choose.

  1. A solution would be, like in the example, to give to the factory the responsibility to instantiate the dependencies.

Problems: The same ones as not using depency injection.

  1. Another one is to give dependencies to the factory constructor

Problems: There will be a lot of parameters in the constructors and the list can grow up

  1. A third solution that I also found in internet is to create kind of builders instead of events. The factory keeps the responsibility to know which kind of object to create and the builders will know how to create them.

Problems: Is the role of the builder DP to handle dependencies? I'm afraid to get the same issues as solution #1.

What should we do ?

Ben

Upvotes: 1

Views: 148

Answers (1)

Sam Holder
Sam Holder

Reputation: 32936

Personally I would go with option 2. Builders are usually used when you want to configure the building but hide the implementation from the client. When you only have to pass the parameters then a factory is usually better.

If you are worried about the number of parameters then you could either pass a parameter object to the factory, or produce single responsibility factories which each know the type of thing they create and how to create it and then assemble them into a chain of responsibility, asking each one if it can create the requested type and passing it along if it can't, or even just a simple list of 'single type factory' instances.

That way each 'factory' only has the dependencies it needs, and the chain simply orchestrates the available factories and so only needs dependencies on them, knowing nothing about what dependencies they have.

Not using the chain of responsibility is simpler. Some solution like this:

public class EventFactory
{
    IEnumerable<ISingleTypeEventFactory> factories

    public EventFactory(IEnumerable<ISingleTypeEventFactory> factories)
    {
         this.factories = factories;
    }


    public Event CreateEvent($type)
    {
         foreach(factory in factories)
         {
              if (factory.CanHandleType($type))
              {
                   return factory.CreateEvent($type);
              }
         }
    }
}

Upvotes: 3

Related Questions