Abstract Factory Design Pattern
Abstract factory design pattern, like a simpler factory design pattern, belongs to creational design patterns. This pattern is similar to factory design pattern with a one core difference. It adds another layer of abstraction, but for factories. So this pattern not only provides an abstraction for creating objects of a concrete type, but also an abstraction to retrieve a factory of a concrete type that can create our desired object. To retrieve a factory we use a factory provider.
First of all, we need an interface that specifies some basic logic our classes must implement and also an interface that describes logic for a factory. Our factory will produce objects of two types: a Vehicle
and a Paint
for that vehicle. Two concrete factories will be created with one producing a Car
and a Red
paint and a second one producing a Truck
and a Green
paint. So let's define our interfaces.
public interface Vehicle {
String getName();
}
public interface Paint {
String getName();
}
Next we need some implementations of our Vehicle
, i.e. Car
and Truck
and some implementations of our Paint
, i.e. Red
and Green
.
public class Car implements Vehicle {
@Override
public String getName() {
return "Car";
}
}
public class Truck implements Vehicle {
@Override
public String getName() {
return "Truck";
}
}
public class Red implements Paint {
@Override
public String getName() {
return "Red";
}
}
public class Green implements Paint {
@Override
public String getName() {
return "Green";
}
}
An interface specifying our logic for a factory and implementations of that interface is as follows.
public interface Factory {
public Vehicle createVehicle();
public Paint createPaint();
}
public class CarFactory implements Factory {
@Override
public Vehicle createVehicle() {
return new Car();
}
@Override
public Paint createPaint() {
return new Red();
}
}
public class TruckFactory implements Factory {
@Override
public Vehicle createVehicle() {
return new Truck();
}
@Override
public Paint createPaint() {
return new Green();
}
}
The last thing we need is a factory provider, which will provide us a factory for vehicles and their paint. Our example also uses switch expression first introduced in java 12 and available in java 14.
public class FactoryProvider {
public static Factory getFactory(String type) {
return switch (type) {
case "CAR" -> new CarFactory();
case "TRUCK" -> new TruckFactory();
default -> throw new IllegalArgumentException("Factory of type " + type + " was not recognized");
};
}
}
Thanks to our provider we get our desired factory that can produce a vehicle and a paint for that vehicle without a user to know the creation logic of those objects. Creation of objects of concrete type is solely handled by factories. Next sample shows usage of this pattern.
public class App {
public static void main(String[] args) {
Factory carFactory = FactoryProvider.getFactory("CAR");
Vehicle car = carFactory.createVehicle();
Paint carPaint = carFactory.createPaint();
// Prints: Created a vehicle of type: Car and paint: Red
System.out.println("Created a vehicle of type: " + car.getName() + " and paint: " + carPaint.getName());
Factory truckFactory = FactoryProvider.getFactory("TRUCK");
Vehicle truck = truckFactory.createVehicle();
Paint truckPaint = truckFactory.createPaint();
// Prints: Created a vehicle of type: Truck and paint: Green
System.out.println("Created a vehicle of type: " + truck.getName() + " and paint: " + truckPaint.getName());
}
}
Conclusion
That's it! We created and implemented an example of abstract factory pattern. Simple and easy.