A GUIDE TO SOFTWARE DESIGN PATTERNS
Creational Design Pattern: Abstract Factory
Definition
The abstract factory pattern is a creational pattern that provides a way to encapsulate a group of individual factories that have a common theme without specifying their concrete classes.
If you are familiar with the factory method, you’ll see a lot of similarities in the abstract factory. However, if you aren’t, then I would suggest you check out Creational Design Pattern: Factory Method. In plain English, you could say the abstract factory pattern is simply a way of grouping many similar factories into one factory with indicative parameters. These parameters tell your abstract factory class which sub-factories and derived classes to use. I will provide some sample code in Java that clarifies this further.
Usage
When should this pattern be used? I find it easier to use real-world scenarios when explaining programming concepts. So let’s use one to demonstrate good use of this pattern.
Let’s say you’re working on a package that creates vehicles. Your package must take into account both a vehicle body type( e.g SUV, sedan, coupe, convertible, hatchback, truck, etc…) and energy type (e.g Gas, hybrid and electric). For brevity, I’ll only work with two body types: Sedan and SUV. The consumers of your package don’t care about its implementation, however, you do. Why? Because you have to maintain it.
It’s crucial to make sure you design it with the solid principle in mind (if you’re not familiar with the SOLID principles, check out S.O.L.I.D Principles Explained In Five Minutes). Doing that from the start will save you so many headaches in the future.
Implementation
A good approach to solving this problem is to start with a Vehicle interface with common behaviors for your base class. All cars must be drivable and need a way to fill-up. Electric cars need to be charged, gas cars need to be fueled and hybrid cars do both. Let’s supposed all cars have some kind of greeting message on the dashboard when you put the key in the ignition.
So the Vehicle interface would look like this.
public interface Vehicle {
void drive();
void fillUp();
void greetDriver();
}Now that I’ve captured all the behaviors the interface will provide, I also need a way to capture the body type and energy type. So let’s create two enums: CarBodyType and EnergyType.
public enum CarBodyType {
Sedan,
SUV
}public enum EnergyType {
Gas,
Hybrid,
Electric
}All cars must be drivable, but driving an electric might differ from a hybrid. The same goes for a gas-powered car. So I need a blueprint for gas, hybrid and electric cars. Let’s create a base class for each energy type car that implement the Vehicle interface. The classes’ names will be HybridVehicle, GasVehicle, and ElectricVehicle.
Here’s the code for the HybridVehicle class.
abstract class HybridVehicle implements Vehicle {
private CarBodyType type;HybridVehicle(CarBodyType type){
this.type = type;
}@Override
public void drive() {
System.out.println("Driving an hybrid " + type);
}@Override
public void fillUp() {
System.out.println("your hybrid " +
type + " is fueling or charging...");
}@Override
public String toString() {
return "\nEnergyType=Hybrid BodyType=" + type;
}
}Here’s the code for the GasVehicle class
abstract class GasVehicle implements Vehicle {
private CarBodyType type;GasVehicle(CarBodyType type){
this.type = type;
}@Override
public void drive() {
System.out.println("Driving a gas " + type);
}@Override
public void fillUp() {
System.out.println("your gas " +
type + " is fueling...");
}@Override
public String toString() {
return "\nEnergyType=Gas BodyType=" + type;
}
}Here’s the code for the ElectricVehicle class
abstract class ElectricVehicle implements Vehicle {
private CarBodyType type;ElectricVehicle(CarBodyType type){
this.type = type;
}@Override
public void drive() {
System.out.println("Driving an electric " + type);
}@Override
public void fillUp() {
System.out.println("your electric " +
type + " is Charging...");
}@Override
public String toString() {
return "\nEnergyType=Electric BodyType=" + type;
}
}Now that I have the base class for each energy type, I can proceed to create a class that matches the body type for each energy type — i.e., I’ll create an electric sedan class, a hybrid sedan class, and a gas sedan class. I’ll repeat the process for SUV. I have three energy types and two body types, so I’ll end up with six classes.
Here’s the code for our hybrid vehicles’ classes.
class HybridSedan extends HybridVehicle {
HybridSedan() {
super(CarBodyType.Sedan);
}@Override
public void greetDriver() {
System.out.println("Greeting from your hybrid "
+ CarBodyType.Sedan);
}
}class HybridSUV extends HybridVehicle {
HybridSUV() {
super(CarBodyType.SUV);
}@Override
public void greetDriver() {
System.out.println("Greeting from your hybrid "
+ CarBodyType.SUV);
}
}Here’s the code for our electric vehicles’ classes.
class ElectricSedan extends ElectricVehicle {
ElectricSedan() {
super(CarBodyType.Sedan);
}@Override
public void greetDriver() {
System.out.println("Greeting from your electric "
+ CarBodyType.Sedan);
}
}class ElectricSUV extends ElectricVehicle {
ElectricSUV(){
super(CarBodyType.SUV);
}@Override
public void greetDriver() {
System.out.println("Greeting from your electric "
+ CarBodyType.SUV);
}
}Here’s the code for our gas vehicles’ classes.
class GasSedan extends GasVehicle {
GasSedan() {
super(CarBodyType.Sedan);
}@Override
public void greetDriver() {
System.out.println("Greeting from your gas "
+ CarBodyType.SUV);
}
}class GasSUV extends GasVehicle {
GasSUV() {
super(CarBodyType.SUV);
}@Override
public void greetDriver() {
System.out.println("Greeting from your gas "
+ CarBodyType.SUV);
}
}Now that I have all these classes, how do I know which one to return? That’s where knowledge of the factory method comes in handy. then I’ll group our factory classes under another factory class that will take two parameters. These parameters will be used as indicators for which class to return. Let’s start with the hybrid factory. I’ll name it HybridVehicleFactory.
Here’s the code.
class HybridVehicleFactory {
private HybridVehicleFactory(){}static Vehicle GetInstance(CarBodyType type){
switch (type){
case SUV:
return new HybridSUV();
case Sedan:
return new HybridSedan();
default:
throw new UnsupportedOperationException(
"enum " + type + "not supported.");
}
}
}Two things to notice here. The constructor is made private to prevent the instantiation of the factory. The default access modifier is used to make sure the factory is only accessible within the package.
The body type will be used in each factory to determine which class to return. So let’s create the two remaining factories: GasVehicleFactory and ElectricVehicleFactory.
Here’s the code for both.
class GasVehicleFactory {
private GasVehicleFactory(){}static Vehicle GetInstance(CarBodyType type){
switch (type){
case SUV:
return new GasSUV();
case Sedan:
return new GasSedan();
default:
throw new UnsupportedOperationException("" +
"enum " + type + "not supported.");
}
}
}class ElectricVehicleFactory {
private ElectricVehicleFactory(){}static Vehicle GetInstance(CarBodyType type){
switch (type){
case SUV:
return new ElectricSUV();
case Sedan:
return new ElectricSedan();
default:
throw new UnsupportedOperationException(
"enum " + type + "not supported.");
}
}
}Now that I know which class to return for each body type, how do I know which factory to use? The energy type parameter will be used for that. This is the difference between the abstract factory and the factory method. I need to create another factory with one static method that takes two parameters. That factory will call a different factory based on the energy type. Let’s create a factory named VehicleFactory.
Here’s the code.
public class VehicleFactory {
private VehicleFactory(){}public static Vehicle CreateInstance(CarBodyType type,
EnergyType energyType){
switch (energyType){
case Gas:
return GasVehicleFactory.GetInstance(type);
case Hybrid:
return HybridVehicleFactory.GetInstance(type);
case Electric:
return ElectricVehicleFactory.GetInstance(type);
default:
throw new UnsupportedOperationException(
"EnergyType " + energyType +
" not supported.");
}
}
}To get a car of certain energy and body type, all I need to do is call the VehicleFactory and specify the body and energy type then an instance of a Vehicle class will be created for us. The scenario is that you pull to a gas or charging station and fill up your tank, you start your car, then you drive. Let’s now write a sample code that creates a few vehicles that simulate that scenario.
Here’s the code.
public static void main(String[] args) {Vehicle hybridSedan = VehicleFactory.CreateInstance(
CarBodyType.Sedan,
EnergyType.Hybrid);System.out.println(hybridSedan);
hybridSedan.fillUp();
hybridSedan.greetDriver();
hybridSedan.drive();Vehicle gasSUV = VehicleFactory.CreateInstance(
CarBodyType.SUV,
EnergyType.Gas);System.out.println(gasSUV);
gasSUV.fillUp();
gasSUV.greetDriver();
gasSUV.drive();Vehicle electricSedan = VehicleFactory.CreateInstance(
CarBodyType.Sedan,
EnergyType.Electric);System.out.println(electricSedan);
electricSedan.fillUp();
electricSedan.greetDriver();
electricSedan.drive();}
If you run this code, your output should look like this.
EnergyType=Hybrid BodyType=Sedan
your hybrid Sedan is fueling or charging...
Greeting from your hybrid Sedan
Driving an hybrid SedanEnergyType=Gas BodyType=SUV
your gas SUV is fueling...
Greeting from your gas SUV
Driving a gas SUVEnergyType=Electric BodyType=Sedan
your electric Sedan is Charging...
Greeting from your electric Sedan
Driving an electric SedanTo create a hybrid sedan, you call the VehicleFactory.CreateInstance static method, and VOILA. Because the VehicleFactory class always returns the Vehicle interface, you can change any vehicle type and your code should still work. Thank you for making it to the end.
Happy coding.
