The Abstract Factory design pattern in Java is a creational pattern that provides an interface (Abstract Factory) to create families of related objects without specifying their concrete classes. Concrete factory classes implement the interface to create specific object families. This pattern allows the client code to create objects without knowing their exact implementations, promoting flexibility and easy addition of new object families.
Abstract factory design pattern is similar to Factory design pattern; just the difference is that it is more like the factory to factories.
When to use Abstract factory design pattern?
- Different Platforms
- When we want our code to work on different platforms or systems (such as Windows or macOS), Abstract factory helps us create objects that match the configuration on each platform and run successfully without mixing them up.
- Example: Consider we are making a game that runs on both Android and iOS. Using Abstract factory, we can create a factory for each platform that makes buttons and menus in the right style. In this way, we don’t accidentally use Android buttons on iOS.
- Groups of Objects
- If we need to create several related things that work together, like different styles of buttons and check-boxes, Abstract factory helps us ensure that they fit and work well together.
- Example: Let’s say we are building a mobile app that lets users customize the theme of the mobile. Users can choose between different themes for their mobile, like “classic,” “modern,” and “funky.” Each theme includes a specific style for buttons and check-boxes, which can be easily implemented with the help of an abstract factory design pattern.
- Adding New Stuff
- If you plan to add new types of things in the future, like new types of buttons, using Abstract Factory makes it easier to slot them in without confusing existing parts.
- Example: If we are building a control panel for a spaceship game and we have buttons for “Launch”, “Landing”, and “Emergency Stop”, we have used Abstract Factory to make these buttons. After some time, we decided to add more buttons for “Shield Activation” and “Communication”. Using Abstract Factory, we can add a new factory for each type of button. In this way, we can add new buttons without disturbing the old buttons and features.
- Easy Changes
- It helps keep your code neat when you want to change how objects are made or make changes to a group of objects. You can do this in one place.
Example
We will learn about Abstract factory design patterns with the help of the Clash of Clans game, which we used in our previous tutorial for Factory design patterns. In this tutorial, we extend that example to implement the Abstract factory design pattern.
In the above picture, the CharacterFactory is our abstract factory, and it is used to create families of related objects. i.e., ArcherCharacterFactory and WizardCharacterFactory; that’s why it is called the Factory of Factories.
Step-by-step implementation of the Abstract factory design pattern
Step 1- Create an interface
First, we need to create an interface Character, which represents the common properties of each character. It defines the methods that all character classes must implement. Concrete character classes Archer and Wizard will implement this interface and provide specific implementation of its methods.
/**
* Character - This interface will define the common
* properties which must be implemented by all the
* characters of game.i.e, Archer and Wizard
*
* @author paulsofts
*/
public interface Character {
void selectCharacter();
void usePower();
}
Step 2- Create Archer and Wizard concrete classes
In this step, we will create the concrete character classes that implement the Character interface and provide the implementation of the character interface’s methods.
public class Archer implements Character {
@Override
public void selectCharacter() {
System.out.println("Selected character: Archer");
}
@Override
public void usePower() {
System.out.println("Power: Deploy multiple arrows for area damage!");
}
}
Similarly, we create the Wizard class and implement the Character interface.
public class Wizard implements Character {
@Override
public void selectCharacter() {
System.out.println("Selected character: Wizard");
}
@Override
public void usePower() {
System.out.println("Power: Cast a fireball that deals splash damage!");
}
}
Step 3- Create CharacterFactory
This is the Abstract Factory. It’s an interface that declares the method createCharacter(), which concrete factories implement to create instances of characters. The CharacterFactory is responsible for creating families of related objects, different types of characters.
/**
* CharcterFactory - Abstract Factory
*
* CharcterFactory - Concrete factories will
* implements this factory to create instances
* of characters
*
* @author paulsofts
* */
public interface CharacterFactory {
Character createCharacter();
}
Step 4- Create factories for different characters
In this step, we will create the factory classes for different characters available in our game, which will further implement the CharacterFactory and provide the implementation for the createCharacter() method.
public class ArcherCharacterFactory implements CharacterFactory {
@Override
public Character createCharacter() {
return new Archer();
}
}
In a similar way, we define the WizardCharacterFactory.
public class WizardCharacterFactory implements CharacterFactory {
@Override
public Character createCharacter() {
return new Wizard();
}
}
Step 5- Client Code
Finally, we create our main class. i.e, ClashOfClans. Let’s understand how it’s working. For example, if the user wants to create an Archer game character, they will call ArcherCharacterFactory, which internally calls the CharacterFactory (AbstractFactory). This is known as Factory to Factories, and the CharacterFactory creates the object of the Archer game character. This Archer object is used to initialise the common properties of the Character interface.
package com.paulsofts.abstractfactorypattern;
public class ClashOfClans {
public static void main(String[] args) {
CharacterFactory archerFactory = new ArcherCharacterFactory();
CharacterFactory wizardFactory = new WizardCharacterFactory();
Character archer = archerFactory.createCharacter();
Character wizard = wizardFactory.createCharacter();
archer.selectCharacter();
archer.usePower();
wizard.selectCharacter();
wizard.usePower();
}
}
Step 6- Test Application
Now, we run our ClashOfClains class and test our application.
Difference between Factory and Abstract Factory design pattern
Aspect | Factory Design Pattern | Abstract Factory Pattern |
Intent | Factory pattern is used to create the single type objects. It specifies the sub-class to decide which concrete class will be instantiated. | Abstract factory pattern provides an interface for creating the families of related objects without specifying their concrete classes. |
Abstraction | Simple and low level of abstraction. | Complex and higher level of abstraction. |
Flexibility | It has less flexibility as it mainly concern with creating objects of single type. | It offers more flexibility in adopting new type of product or changes. |
Example | Creating instances of various bank cards such as debit card, credit card etc. | Creating different types of UI components such as buttons, checkboxes and other screen elements as they are families of related objects. |