Java > Design Patterns in Java > Creational Patterns > Factory Method

Factory Method Pattern: Creating Objects with Flexibility

The Factory Method pattern is a creational design pattern that defines an interface for creating an object, but lets subclasses decide which class to instantiate. It promotes loose coupling by delegating the instantiation logic to subclasses, allowing you to add new product types without modifying existing code. This example demonstrates how to implement the Factory Method pattern in Java to create different types of shapes.

Core Concepts

The Factory Method pattern revolves around abstracting the object creation process. The key players are: * **Product:** The interface or abstract class that defines the type of object the factory method creates. * **ConcreteProduct:** Concrete implementations of the Product interface. * **Creator:** The abstract class or interface which declares the factory method. This method returns an object of a Product type. The Creator also usually contains core business logic that relies on Product objects. * **ConcreteCreator:** Subclasses of the Creator that override the factory method to return an instance of a specific ConcreteProduct.

Example: Shape Factory

This code demonstrates a simple shape factory. The `Shape` interface defines the `draw` method. `Circle` and `Rectangle` are concrete implementations of the `Shape` interface. The `ShapeFactory` is the abstract creator class, defining an abstract `createShape` method. `CircleFactory` and `RectangleFactory` are concrete creators, each responsible for creating their respective shapes. The `FactoryMethodExample` class shows how to use the factories to create and draw shapes. The drawShape method demonstrates how the creator can implement core logic utilizing the created products.

interface Shape {
    void draw();
}

class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("Drawing Circle");
    }
}

class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("Drawing Rectangle");
    }
}

abstract class ShapeFactory {
    public abstract Shape createShape();

    public Shape drawShape() { // Example of business logic using the product.
        Shape shape = createShape();
        shape.draw();
        return shape;
    }
}

class CircleFactory extends ShapeFactory {
    @Override
    public Shape createShape() {
        return new Circle();
    }
}

class RectangleFactory extends ShapeFactory {
    @Override
    public Shape createShape() {
        return new Rectangle();
    }
}

public class FactoryMethodExample {
    public static void main(String[] args) {
        ShapeFactory circleFactory = new CircleFactory();
        Shape circle = circleFactory.createShape();
        circle.draw();

        ShapeFactory rectangleFactory = new RectangleFactory();
        Shape rectangle = rectangleFactory.createShape();
        rectangle.draw();

        //Example use of drawShape
        Shape circle2 = circleFactory.drawShape();
    }
}

Real-Life Use Case

Consider a UI framework that needs to support different button styles (e.g., standard button, round button, gradient button). Using the Factory Method pattern, an abstract `ButtonFactory` can define the `createButton` method. Concrete factories, like `StandardButtonFactory` and `RoundButtonFactory`, would then create specific button instances. This allows the UI framework to easily incorporate new button styles without modifying the core button creation logic.

Best Practices

* **Single Responsibility Principle:** Each concrete factory should ideally be responsible for creating one type of product. * **Open/Closed Principle:** The Factory Method pattern allows you to add new product types without modifying existing factory classes. * **Consider Factory Pattern vs. Abstract Factory:** If you need to create families of related objects, the Abstract Factory pattern might be more suitable.

Interview Tip

Be prepared to explain the difference between the Factory Method pattern and the Abstract Factory pattern. Also, be ready to discuss the benefits of using the Factory Method pattern, such as improved code maintainability and flexibility.

When to Use

* When a class can't anticipate the class of objects it must create. * When you want subclasses to specify the objects to be created. * When you want to centralize object creation logic in one place.

Memory Footprint

The memory footprint associated with the Factory Method pattern is generally low. Each concrete factory creates only the objects it's designed to create. However, consider the potential memory overhead if you have a large number of concrete factories or if the objects created by the factories are very large.

Alternatives

Alternatives to the Factory Method pattern include: * **Simple Factory:** A single factory class with a conditional statement (e.g., switch statement) to determine which object to create. This approach is less flexible than the Factory Method pattern. * **Abstract Factory:** Used to create families of related objects. * **Builder Pattern:** Used to construct complex objects step by step.

Pros

* Decouples the client code from concrete classes, promoting loose coupling. * Provides flexibility in object creation by allowing subclasses to decide which class to instantiate. * Makes the code more maintainable and extensible. * Adheres to the Open/Closed Principle.

Cons

* May increase the number of classes in the system, leading to increased complexity. * Requires creating a new concrete factory for each new product type.

FAQ

  • What is the key difference between the Factory Method and the Abstract Factory patterns?

    The Factory Method pattern is used to create a single object type, while the Abstract Factory pattern is used to create families of related objects.
  • When should I use the Factory Method pattern instead of a simple factory?

    Use the Factory Method pattern when you need to support multiple object creation types and want to avoid tight coupling between the client code and concrete object classes. The simple factory might be sufficient if you only have a few object types and don't anticipate adding more.