Seth Barrett

Daily Blog Post: March 19th, 2023

design1

Mar 19th, 2023

Exploring the Abstract Factory Pattern in Java

Welcome back to our series on design patterns for Object-Oriented Programming (OOP) in Java. In this post, we'll be exploring the Abstract Factory Pattern, which is a creational design pattern that provides an interface for creating families of related or dependent objects without specifying their concrete classes.

The Abstract Factory Pattern is used when we need to create families of related objects that are derived from a common base class or interface. It allows us to encapsulate the object creation process and provide a way to create different types of related objects based on certain conditions or parameters.

Let's take a look at the different components of the Abstract Factory Pattern:

  1. Abstract Factory:

    The Abstract Factory is an interface that defines a set of factory methods, one for each type of related object that needs to be created. The Abstract Factory provides an interface for creating families of related objects, without specifying their concrete classes.

  2. Concrete Factory:

    The Concrete Factory is a class that implements the Abstract Factory interface. It is responsible for creating a family of related objects, such as a set of GUI components that have a consistent look and feel.

  3. Abstract Product:

    The Abstract Product is an interface that defines the properties and methods that the Concrete Products must have. It is a common base class or interface for all the products in a family.

  4. Concrete Product:

    The Concrete Product is a class that implements the Abstract Product interface. It is a specific implementation of a product in a family.

Now, let's see an example of how we can implement the Abstract Factory Pattern in Java:

public interface Button {
    public void render();
 }
 
 public class WindowsButton implements Button {
    @Override
    public void render() {
       System.out.println("Rendering Windows button...");
    }
 }
 
 public class MacButton implements Button {
    @Override
    public void render() {
       System.out.println("Rendering Mac button...");
    }
 }
 
 public interface GUIFactory {
    public Button createButton();
 }
 
 public class WindowsGUIFactory implements GUIFactory {
    @Override
    public Button createButton() {
       return new WindowsButton();
    }
 }
 
 public class MacGUIFactory implements GUIFactory {
    @Override
    public Button createButton() {
       return new MacButton();
    }
 }

In this example, we have an interface Button and two Concrete Products, WindowsButton and MacButton, that implement this interface. We also have an abstract GUIFactory class that defines the factory method createButton(). Finally, we have two Concrete Factories, WindowsGUIFactory and MacGUIFactory, that implement the createButton() method to create and return the respective Concrete Product.

Now, let's see how we can use these classes to create related objects:

public class Main {
    public static void main(String[] args) {
       GUIFactory factory;
 
       // Determine the user's operating system
       String os = System.getProperty("os.name").toLowerCase();
       if (os.contains("windows")) {
          factory = new WindowsGUIFactory();
       } else {
          factory = new MacGUIFactory();
       }
 
       Button button = factory.createButton();
       button.render(); // Output: Rendering Windows button... or Rendering Mac button...
    }
 }

In this example, we create a GUIFactory object based on the user's operating system. We then use the factory to create a Button object, and call the render() method on the button to see the respective output.

That's it for our introduction to the Abstract Factory Pattern. We hope you found this post informative and useful. In the next post, we'll explore the Singleton Pattern, which is a creational design pattern that ensures a class has only one instance, and provides a global point of access to it. Stay tuned!