DEV Community

Xavi
Xavi

Posted on • Edited on

Design patterns in Java, a practical approach: The factory pattern

The factory pattern is probably one of the most used patterns by software engineers, it provides a single point from where we can generate different implementations of a given class by any given conditions.

But there is a 'practical' in the title for a reason, so let's get our hands on the code, we will build an animal feeding service!

The Model

For our service to work, we need two things Animals and Food

Since there are lots of different animals and lots of different foods we will first implement their interfaces.

public interface Food {

}
Enter fullscreen mode Exit fullscreen mode
public interface Animal {
    void eat(Food food);
}
Enter fullscreen mode Exit fullscreen mode

We also defined a method in our interface so we make sure our animals can eat.

We have defined how food and animals should look like but right now we don't have anything real, let's change that.

In our feeding service we will be able to feed Cows, Dogs, and Rabbits:

public class Cow implements Animal {

    @Override
    public void eat(Food food) {
    }
}


public class Dog implements Animal {

    @Override
    public void eat(Food food) {
    }
}


public class Rabbit implements Animal {

    @Override
    public void eat(Food food) {
    }
}
Enter fullscreen mode Exit fullscreen mode

We will also need food for every kind of animal:

public class CowFood implements Food {
}
Enter fullscreen mode Exit fullscreen mode
public class DogFood implements Food {
}
Enter fullscreen mode Exit fullscreen mode
public class RabbitFood implements Food {
}
Enter fullscreen mode Exit fullscreen mode

Our Food Factory

Once we have our models we now need a way to get the proper food for each animal.

We can achieve this by using the factory pattern:

public class FoodFactory {

    public Food createFoodFor(Animal animal) {

        if (animal instanceof Rabbit)
            return new RabbitFood();

        if (animal instanceof Dog)
            return new DogFood();

        if (animal instanceof Cow)
            return new CowFood();

        throw new RuntimeException("We don't have food for your animal :(");
    }
}
Enter fullscreen mode Exit fullscreen mode

In this factory, we will have one method that given any animal it will return the right food for them!!

But don't take my word for it, we can now implement the eat method on the animals to make sure they are getting their foods. This is what the implementation for the Cow class looks like:


public class Cow implements Animal {

    @Override
    public void eat(Food food) {

        if (food instanceof CowFood) {
            System.out.println("Cow: Yummy!");
        } else {
            throw new IndigestionException("That was bad..");
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

Putting it all together

We now can finally build our FeedingService:

public class FeedingService {

    private final FoodFactory foodFactory;

    public FeedingService() {
        this.foodFactory = new FoodFactory();
    }

    public void feedAnimal(Animal animal) {
        Food food = foodFactory.createFoodFor(animal);
        animal.eat(food);
    }
}
Enter fullscreen mode Exit fullscreen mode

We now can feed ANY animal without even knowing which animal we have in our hands, the FoodFactory will get the right food so we can feed our animal right away.

We don't want upset animals in production so we test that everything works as planned:

    @Test
    void rabbit_does_not_get_an_indigestion() {
        Rabbit rabbit = new Rabbit();
        feedingService.feedAnimal(rabbit);
    }

    @Test
    void cow_does_not_get_an_indigestion() {
        Cow cow = new Cow();
        feedingService.feedAnimal(cow);
    }

    @Test
    void dog_does_not_get_an_indigestion() {
        Dog dog = new Dog();
        feedingService.feedAnimal(dog);
    }



>>> "Cow: Yummy!"
>>> "Cat: Yummy!"
>>> "Rabbit: Yummy!"
Enter fullscreen mode Exit fullscreen mode

So that's about it! We got our feeding service up and running, powered by our food factory!

Feel free to leave questions in the comments.

You can find all the code used in this example here.

You also can follow me on twitter @xavigrimau.

Top comments (0)