Abstract Design Pattern
Let’s take a look at the abstract factory design pattern in java with a real-world example. Abstract factory pattern in java is a creational pattern. It is based on factory pattern but goes one level deep to create the factory of factories. This pattern deals with similar factories by grouping them.
In abstract factory pattern, The calling application(client) doesn’t even know which factory creates the object for them. All of this is possible through interfaces. For example, Take a look at an application that runs on both Windows and Linux.
If you are designing a program that runs on both Windows and macOS, you should write a lot of conditions to display elements. But with the use of a design pattern, you could easily detach logic based on the OS type. Here is a simple illustration of how to do that.
Implement Abstract Factory Design Pattern
The abstract factory pattern applies when the client needs to create an object and many Factories could supply it. This pattern uses a Factory of Factories that acts as a mediator to find the appropriate factory. If you think about it, it’s just the Factory Pattern with extra steps.
So let’s jump right into the example.
Step 1: Create a common interface
First, You need a common interface the client would use to access the object. In this case, we are using the Button interface. As it is an interface client doesn’t need to know whether it gets a WindowsButton or MacOSButton.
public interface Button {
void onClick();
}
Code language: PHP (php)
Down the line, A set of factory classes will create objects of type Button. They all will be tied together with the help of Abstract Factory Pattern.
Step 2: implement Button Interface
Next, implement the concrete classes for the button interfaces. The client expects an object from one of these classes. For this example, We are creating two types of buttons for both Windows and Mac.
public class MacButton implements Button {
@Override
public void onClick() {
System.out.println("You clicked a Mac OS Button");
}
}
Code language: Java (java)
public class RoundedMacButton extends MacButton {
@Override
public void onClick() {
System.out.println("You clicked a 'Rounded' Mac OS Button");
}
}
Code language: Java (java)
public class WindowsButton implements Button {
@Override
public void onClick() {
System.out.println("You clicked a windows Button");
}
}
Code language: Java (java)
public class RoundedWindowsButton extends WindowsButton {
@Override
public void onClick() {
System.out.println("You clicked a 'Rounded' Windows Button");
}
}
Code language: Java (java)
As you see, All these four classes implement the Button interface. Next we need to create the factories that can build these objects.
Step 3: Create An Abstract factory
As we know from the factory pattern, the client needs a regular or rounded Button object. And we know that it can get it from a factory. But there is one problem. The client doesn’t know whether to use Windows or Mac buttons. In this case, we need to provide a common abstraction via a generic ButtonFactory
. This interface will be the abstraction for our Mac and Windows button factories.
public abstract class ButtonFactory {
public abstract Button createButton(boolean rounded);
}
Code language: PHP (php)
Step 4: Implement Button Factories
Next, We need to create ButtonFactories that could supply Windows/Mac buttons.
public class WindowsButtonFactory extends ButtonFactory {
@Override
public WindowsButton createButton(boolean rounded) {
if(rounded){
return new RoundedWindowsButton();
} else {
return new WindowsButton();
}
}
}
Code language: PHP (php)
public class MacOsButtonFactory extends ButtonFactory {
@Override
public MacButton createButton(boolean rounded) {
if (rounded) {
return new RoundedMacButton();
} else {
return new MacButton();
}
}
}
Code language: PHP (php)
Note that the return types make sure MacOsButtonFactory only returns a Mac button. But regardless, the client can treat both the same way.
Step 5: Create a Factory of Factories
Finally, We need to create a factory provider/generator that supplies a ButtonFactory object for the client.
public class ButtonFactoryProvider {
public static ButtonFactory getFactory(String osName) {
if (osName.equals("windows")) {
return new WindowsButtonFactory();
} else if (osName.equals("mac")) {
return new MacOsButtonFactory();
} else {
throw new RuntimeException("Not implemented yet");
}
}
}
Code language: Java (java)
Step 6: Test the Abstract Factory Pattern
To test our setup, we need to write a simple main class that tries to create Button objects.
public class AbstractFactoryPatternExample {
public static void main(String[] args) {
ButtonFactory buttonFactory = ButtonFactoryProvider.getFactory("windows");
Button button = buttonFactory.createButton(false);
button.onClick();
button = buttonFactory.createButton(true);
button.onClick();
buttonFactory = ButtonFactoryProvider.getFactory("mac");
button = buttonFactory.createButton(false);
button.onClick();
button = buttonFactory.createButton(true);
button.onClick();
}
}
Code language: Java (java)
When we run this class You should see the following output.
To summarize, We learned how to implement abstract factory design pattern in java with a real world example.