In this new post, Java Supplier Interface and Factory Pattern, we are going to see and understand a bit better the usage and purpose of Java Supplier.
This interface works similarly to the Factory Pattern, so let’s start by looking at this pattern.
What is the Factory Pattern?
The Factory Pattern ranks among the most commonly used patterns in software design and construction. In this pattern, we create an object without exposing the creation logic and refer to the new object through a common interface.
Let’s understand it better with an example. We’ll start with an animal class, and from that class, we’ll have two classes: Dog and Cat, which will implement the animal class.
Now let’s build the 3 classes, where Dog and Cat are two classes that extend the Animal superclass. The idea is to get the number of legs based on the animal.
package com.refactorizando.supplier; public abstract class Animal { public abstract int patas(); }
package com.refactorizando.supplier; public class Perro extends Animal { private int patas; public Perro() { this(4); } public Perro(int patas) { super(); this.patas = patas; } public int getPatas() { return patas; } public void setPatas(int patas) { this.patas = patas; } @Override public int patas() { return patas; } }
package com.refactorizando.supplier; public class Gato extends Animal { private int patas; public Gato() { this(4); } public Gato(int patas) { super(); this.patas = patas; } public int getPatas() { return patas; } public void setPatas(int patas) { this.patas = patas; } @Override public int patas() { return patas; } }
package com.refactorizando.supplier; public class Avestruz extends Animal { private int patas; public Avestruz() { this(2); } public Avestruz(int patas) { super(); this.patas = patas; } public int getPatas() { return patas; } public void setPatas(int patas) { this.patas = patas; } @Override public int patas() { return patas; } }
Once we have defined the three classes, let’s see how to use one or the other based on our needs:
package com.refactorizando.supplier; public class FactoriaAnimales { public static Animal obtenerPatasAnimal(String tipo) { if (tipo.equalsIgnoreCase("Avestruz")) { return new Avestruz(); }else if (tipo.equalsIgnoreCase("Perro")){ return new Perro(); } else { return new Gato(); } } }
package com.refactorizando.supplier; public class Animales { public static void main(String[] args) { Animal animal=FactoriaAnimales.obtenerPatasAnimal("Avestruz"); System.out.println(animal.patas()); } }
In this case, we would get an output of 2 (the ostrich has two legs). Now let’s see how we would do it using a Supplier.
Java Supplier Interface
The Java Supplier interface belongs to the java.util.function package and was introduced in Java 8 to enable functional programming with Java. It represents a function that takes no arguments and returns a generic value of type T.
To use it, the get
method is invoked to produce a value from the lambda expression assigned to an object.
Let’s see its usage based on the previous example of our Animal Factory:
package com.refactorizando.supplier; import java.util.HashMap; import java.util.function.Supplier; public class FactoriaSupplierAnimal { private static final String PERRO = "perro"; private static final String GATO = "gato"; private static final String AVESTRUZ = "avestruz"; private static HashMap<String, Supplier<Animal>> animalMap= new HashMap<>(); static { animalMap.put(AVESTRUZ, Avestruz::new); animalMap.put(PERRO, Perro::new); animalMap.put(GATO, Gato::new); } public static Animal getAnimal(String tipo) { if (animalMap.get(tipo)!=null) { return animalMap.get(tipo).get(); } throw new IllegalArgumentException("Animal not found"); } }
Similar to the Factory Pattern, here we have relied on the Supplier to have a reference to the object creation, for example, Ostrich::new
. This way, we can retrieve the object or incorporate more into the implementation.
To retrieve the object through the Supplier, we use get()
, as mentioned earlier, to produce a value from the assigned lambda expression.
Conclusion
We explored Java Supplier Interface and Factory Pattern, understanding its functionality and implementation. Despite its limited usage, Java Supplier Interface is valuable in applications for reducing boilerplate code and implementing the Factory Pattern effectively.