Design Patterns – Benefits of Using Abstract Factory Over Interfaces

abstract-factorydesign-patternsfactory

I get the idea of the factory pattern, but I feel that it is really not necessary to use this pattern.

For example, below is some code I saw (C#) that use factory method:

public interface IAnimal
{
   void Speak();
}

public class Dog : IAnimal
{
   public void Speak()
   {
      Console.WriteLine("Dog says: Bow-Wow.");
   }
}

public class Tiger : IAnimal
{
   public void Speak()
   {
      Console.WriteLine("Tiger says: Halum.");
   }
}

public abstract class IAnimalFactory
{
   public abstract IAnimal CreateAnimal();
}

public class TigerFactory : IAnimalFactory
{
   public override IAnimal CreateAnimal()
   {
      return new Tiger();
   }
}

public class DogFactory : IAnimalFactory
{
   public override IAnimal CreateAnimal()
   {
      return new Dog();
   }
}

and client can invoke:

IAnimalFactory tigerFactory = new TigerFactory();
IAnimal aTiger = tigerFactory.MakeAnimal();
aTiger.Speak();  //3 lines of code, plus needing of extra factory classes

but Client can also do like:

IAnimal aTiger = new Tiger();
aTiger.Speak();  //only 2 lines of code

we can see that only 2 lines of code is needed, and we don't need to define factory classes.
so why takes extra steps to define and use factories?

Ant P replied that RandomNumberOfAnimalsGenerator needs a factory, but below is my version of the class, still doesn't need any factory.

public class RandomNumberOfAnimalsGenerator
{
    private readonly animal ;

    public RandomNumberOfAnimalsGenerator(IAnimal animal)
    {
        this.animal = animal;
    }

    public List<IAnimal> GetAnimals()
    {
        var animals = new List<IAnimal>();
        var n = RandomNumber();

        for(int i=0; i<n; i++)
        {
            animals.Add(animal);
        }

        return animals;
    }
}

and client invokes:

var RandomNumberOfAnimalsGenerator = new RandomNumberOfAnimalsGenerator(new Tiger());

still doesn't need a factory

Best Answer

I'm not sure yet another answer is needed here, but you asked for your code to be modified to explain the purpose of factories. So perhaps the following will help.

Firstly, I'm going to change your IAnimalFactory to be an interface, rather than an abstract class. It serves no useful purpose being the latter. Also, we likely will have some criteria around what sort of animal we want for a specific circumstance. So let's have an enum that defines that criteria:

public enum AnimalType
{
    Pet,
    Wild
}

Then we can create our factory interface:

public interface IAnimalFactory
{
    IAnimal CreateAnimal(AnimalType typeofAnimal);
}

So now we have a means of letting other parts of the code create an animal, without having to know anything about what animals exist. We simply get to specify whether we want a wild one or not:

public void CreateAWildAnimalAndMakeItTalk(IAnimalFactory factory)
{
    var animal = factory.CreateAnimal(AnimalType.Wild);
    animal.Speak();
}

The only thing left to do is create an actual factory. Let's keep that simple:

internal class SimpleAnimalFactory : IAnimalFactory 
{
    public IAnimal CreateAnimal(AnimalType typeofAnimal)
    {
       return typeofAnimal == AnimalType.Wild ? new Tiger() : new Dog();
    }
}

And then it gets used elsewhere in the code:

CreateAWildAnimalAndMakeItTalk(new SimpleAnimalFactory());

But dogs can be wild too, so we might want to offer a different implementation of the factory:

internal class RandomWildAnimalFactory : IAnimalFactory 
{
    private Random _random = new Random();

    public IAnimal CreateAnimal(AnimalType typeofAnimal)
    {
        if (typeofAnimal == AnimalType.Pet) return new Dog();

        return _random.Next(2) == 0 ? new Tiger() : new Dog();
    }
}

Then we can call our method with the new factory, without having to change any other code:

CreateAWildAnimalAndMakeItTalk(new RandomWildAnimalFactory());
Related Topic