Implement the factory pattern using Lambda expressions in Java 8
- 2020-06-19 10:15:12
- OfStack
preface
The factory pattern is one of the most familiar design patterns in object-oriented design patterns. The traditional implementations are familiar, but today I'll introduce you to a more elegant implementation of the factory pattern using Java8 Lambda expressions.
The cover
The factory pattern, one of the most commonly used design patterns in java, provides a good way to instantiate objects and is a common alternative to the new pattern. Factory design patterns allow you to instantiate object logic without exposing it to clients.
In the following article I will give an example of implementing the factory pattern using traditional code and then re-implementing it using Java8 Lambada
One example
I will first create an Shape interface and several implementation classes, then implement ShapeFactory in the next steps, and finally give a detailed invocation instance and output.
New interface: ES29en.java
public interface Shape {
void draw();
}
Define two implementation classes for Shape: ES35en.java & Rectangle.java
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}
Create a factory class for Shape and implement a factory method that returns a different Shape based on the specified parameters:
public class ShapeFactory {
//use getShape method to get object of type shape
public Shape getShape(String shapeType){
if(shapeType == null){
return null;
}
if(shapeType.equalsIgnoreCase("CIRCLE")){
return new Circle();
} else if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
}
return null;
}
}
ShapeFactory returns a different Shape based on the incoming shapeType.
Here's an example of how to use it.
public class FactoryPatternDemo {
public static void main(String[] args) {
ShapeFactory shapeFactory = new ShapeFactory();
//get an object of Circle and call its draw method.
Shape shape1 = shapeFactory.getShape("CIRCLE");
//call draw method of Circle
shape1.draw();
//get an object of Rectangle and call its draw method.
Shape shape2 = shapeFactory.getShape("RECTANGLE");
//call draw method of Rectangle
shape2.draw();
}
}
Program output
Inside Circle::draw() method.
Inside Rectangle::draw() method.
Implement the factory pattern using Lambada
The Lambda expression allows us to define an anonymous method and to use it as a functional interface. We also want to be able to implement the same features on existing methods.
Method references have the same properties as lambda expressions (for example, they both need a target type and need to be converted to an instance of a functional interface), but we don't need to provide a method body for a method reference, we can refer to existing methods directly by method name.
The following example shows a constructor reference
Supplier circleSupplier = Circle::new;
Circle circle = circleSupplier.get();
According to the principle of constructor reference, we can rewrite the previous code and define 1 Map to hold shape name and its corresponding constructor reference:
final static Map<String, Supplier> map = new HashMap<>();
static {
map.put("CIRCLE", Circle::new);
map.put("RECTANGLE", Rectangle::new);
}
Now we can use this map to instantiate different shapes
public class ShapeFactory {
final static Map<String, Supplier> map = new HashMap<>();
static {
map.put("CIRCLE", Circle::new);
map.put("RECTANGLE", Rectangle::new);
}
public Shape getShape(String shapeType){
Supplier shape = map.get(shapeType.toUpperCase());
if(shape != null) {
return shape.get();
}
throw new IllegalArgumentException("No such shape " + shapeType.toUpperCase());
}
}
Use factory methods implemented with lambada expressions to create shape objects:
FactoryPatternDemo.java
public class FactoryPatternDemo {
public static void main(String[] args) {
Supplier shapeFactory = ShapeFactory::new;
//call draw method of circle
shapeFactory.get().getShape("circle").draw();
//call draw method of Rectangle
shapeFactory.get().getShape("rectangle").draw();
}
}
Program output
Inside Circle::draw() method.
Inside Rectangle::draw() method.
Here Shape::new can be seen as a shorthand for lambda expressions. Although the variable method reference (as in this example) makes the syntax more compact, it has more explicit semantics -- if the method we want to call has a name, we can call it directly by its name.
If the Shape constructor takes multiple arguments, then you need to re-implement your own Supplier
Such as:
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}
0
conclusion