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 {
}
public interface Animal {
void eat(Food food);
}
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) {
}
}
We will also need food for every kind of animal:
public class CowFood implements Food {
}
public class DogFood implements Food {
}
public class RabbitFood implements Food {
}
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 :(");
}
}
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..");
}
}
}
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);
}
}
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!"
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)