Java > Design Patterns in Java > Creational Patterns > Abstract Factory
Abstract Factory Pattern Example: GUI Factory
This example demonstrates the Abstract Factory pattern by creating GUI elements (buttons and text boxes) for different operating systems (Windows and macOS). The Abstract Factory provides an interface for creating families of related objects without specifying their concrete classes. This promotes flexibility and avoids tight coupling to specific implementations.
Defining the Abstract Products
First, we define the abstract product interfaces: `Button` and `TextBox`. These interfaces declare the common operations that all concrete buttons and text boxes must implement.
Button Interface
The `Button` interface defines the `paint()` method, which is responsible for rendering the button on the screen.
interface Button {
void paint();
}
TextBox Interface
The `TextBox` interface defines the `display()` method, which is responsible for rendering the text box on the screen.
interface TextBox {
void display();
}
Concrete Product Implementations
Next, we create concrete implementations of the `Button` and `TextBox` interfaces for Windows and macOS. Each concrete product is specific to a particular operating system.
Windows Button
The `WindowsButton` class implements the `Button` interface and renders a Windows-style button.
class WindowsButton implements Button {
@Override
public void paint() {
System.out.println("Rendering a Windows button.");
}
}
macOS Button
The `MacOSButton` class implements the `Button` interface and renders a macOS-style button.
class MacOSButton implements Button {
@Override
public void paint() {
System.out.println("Rendering a macOS button.");
}
}
Windows TextBox
The `WindowsTextBox` class implements the `TextBox` interface and renders a Windows-style text box.
class WindowsTextBox implements TextBox {
@Override
public void display() {
System.out.println("Displaying a Windows text box.");
}
}
macOS TextBox
The `MacOSTextBox` class implements the `TextBox` interface and renders a macOS-style text box.
class MacOSTextBox implements TextBox {
@Override
public void display() {
System.out.println("Displaying a macOS text box.");
}
}
Abstract Factory Interface
Now, we define the abstract factory interface, `GUIFactory`. This interface declares the methods for creating the abstract products (buttons and text boxes).
GUIFactory Interface
The `GUIFactory` interface defines the `createButton()` and `createTextBox()` methods, which are responsible for creating concrete buttons and text boxes, respectively.
interface GUIFactory {
Button createButton();
TextBox createTextBox();
}
Concrete Factory Implementations
We create concrete factory implementations for Windows and macOS. Each concrete factory is responsible for creating the appropriate concrete products for its operating system.
Windows Factory
The `WindowsFactory` class implements the `GUIFactory` interface and creates Windows-style buttons and text boxes.
class WindowsFactory implements GUIFactory {
@Override
public Button createButton() {
return new WindowsButton();
}
@Override
public TextBox createTextBox() {
return new WindowsTextBox();
}
}
macOS Factory
The `MacOSFactory` class implements the `GUIFactory` interface and creates macOS-style buttons and text boxes.
class MacOSFactory implements GUIFactory {
@Override
public Button createButton() {
return new MacOSButton();
}
@Override
public TextBox createTextBox() {
return new MacOSTextBox();
}
}
Client Code
The `AbstractFactoryDemo` class demonstrates how to use the Abstract Factory pattern. It creates a GUI factory based on the operating system and then uses the factory to create buttons and text boxes. The `createFactory()` method determines which concrete factory to use based on the operating system.
public class AbstractFactoryDemo {
public static void main(String[] args) {
GUIFactory factory = createFactory();
Button button = factory.createButton();
TextBox textBox = factory.createTextBox();
button.paint();
textBox.display();
}
static GUIFactory createFactory() {
String os = System.getProperty("os.name").toLowerCase();
if (os.contains("win")) {
return new WindowsFactory();
} else {
return new MacOSFactory();
}
}
}
Concepts Behind the Snippet
The core idea is to abstract the creation process of related objects. This promotes loose coupling and allows for easy switching between families of products (e.g., changing the look and feel of the UI by switching the factory). The key concepts are: * Abstract Factory: The interface for creating abstract products. * Concrete Factories: Implementations of the abstract factory that create concrete products. * Abstract Products: Interfaces for related products. * Concrete Products: Implementations of the abstract products.
Real-Life Use Case
A common use case is creating UI toolkits for different platforms. Imagine a cross-platform application that needs to render UI elements differently depending on the operating system. The Abstract Factory pattern allows you to create platform-specific UI components without tightly coupling the application logic to the specific UI implementations. Other use cases include document processing (creating different types of documents based on format) and game development (creating different character types based on the game level).
Best Practices
Interview Tip
Be prepared to explain the benefits of using the Abstract Factory pattern, such as decoupling and flexibility. Also, be ready to discuss when it is appropriate to use this pattern (e.g., when you need to create families of related objects that are used together).
When to Use Them
Use the Abstract Factory pattern when: * A system should be independent of how its products are created, composed, and represented. * A system should be configured with one of multiple families of products. * A family of related product objects is designed to be used together, and you need to enforce this constraint. * You want to provide a class library of products, and you want to reveal just their interfaces, not their implementations.
Memory Footprint
The memory footprint of the Abstract Factory pattern depends on the number of factories and products you create. Each factory and product instance will consume memory. However, the pattern itself does not introduce significant overhead. Consider the number of concrete factories and products to be instantiated based on your application needs, and whether or not they are long-lived objects.
Alternatives
Alternatives to the Abstract Factory pattern include: * Factory Method: Simpler to implement when you only need to vary the concrete class that is instantiated. * Builder: Used for constructing complex objects step-by-step. * Prototype: Used for creating new objects by cloning existing objects.
Pros
Cons
FAQ
-
When should I use Abstract Factory vs. Factory Method?
Use Abstract Factory when you need to create families of related objects. Use Factory Method when you need to create a single type of object and want to decouple the object creation from the client code. -
Can Abstract Factory be combined with other creational patterns?
Yes, Abstract Factory can be combined with other creational patterns, such as Builder or Prototype, to create more complex object creation processes.