Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Advanced Java Design Patterns: Factory Pattern

Tech May 14 1

Introduction

Building upon the singleton pattern explored previously, this article examines the factory pattern—a fundamental creational design pattern. It encompasses three variations: simple factory, factory method, and abstract factory patterns.

Simple Factory Pattern

The simple factory pattern falls under the category of creational patterns, also known as the static factory method pattern. This approach delegates the responsibility of creating specific product instances to a single factory object. Clients merely specify the desired product type, and the factory returns an appropriate instance.

Consider the analogy of gaming on a computer: users simply indicate which game they want to launch, and the system opens it without requiring knowledge of its internal workings.

Below is an implementation example:

public class GameLauncher {
    private static final String LOBSTER = "LOBSTER";
    private static final String DOTA = "DOTA";

    public static void main(String[] args) {
        Game game1 = GameFactory.createGame(LOBSTER);
        Game game2 = GameFactory.createGame(DOTA);
        game1.start();
        game2.start();
    }
}

interface Game {
    void start();
}

class LobsterGame implements Game {
    @Override
    public void start() {
        System.out.println("Playing Lobster...");
    }
}

class DotaGame implements Game {
    @Override
    public void start() {
        System.out.println("Playing Dota...");
    }
}

class GameFactory {
    private static final String LOBSTER = "LOBSTER";
    private static final String DOTA = "DOTA";

    public static Game createGame(String gameType) {
        if (LOBSTER.equalsIgnoreCase(gameType)) {
            return new LobsterGame();
        } else if (DOTA.equalsIgnoreCase(gameType)) {
            return new DotaGame();
        }
        return null;
    }
}

Output:

Playing Lobster...
Playing Dota...

By employing the simple factory pattern, instantiation logic is encapsulated within the factory, hiding implementation details from clients. This simplifies usage and facilitates switching between products by modifying only the factory input. However, extending the system with new types requires updating the factory's conditional logic, violating the open-closed principle when dealing with many new types.

Factory Method Pattern

The factory method pattern is one of the most commonly used design patterns in Java and belongs to the creational category. It defines an interface for creating objects but allows subclasses to determine which class to instantiate. This delays object creation to subclasses.

In contrast to the simple factory, the factory method pattern resolves the issue of tight coupling when adding new product types. Each product has its dedicated factory, reducing dependencies.

Here’s how the revised code looks:

public class GameLauncher {
    private static final String LOBSTER = "LOBSTER";
    private static final String DOTA = "DOTA";
    private static final String WAR = "WAR";

    public static void main(String[] args) {
        Game game1 = new LobsterFactory().createGame();
        Game game2 = new DotaFactory().createGame();
        Game game3 = new WarFactory().createGame();
        game1.start();
        game2.start();
        game3.start();
    }
}

interface Game {
    void start();
}

class LobsterGame implements Game {
    @Override
    public void start() {
        System.out.println("Playing Lobster...");
    }
}

class DotaGame implements Game {
    @Override
    public void start() {
        System.out.println("Playing Dota...");
    }
}

class WarGame implements Game {
    @Override
    public void start() {
        System.out.println("Playing War...");
    }
}

interface GameFactory {
    Game createGame();
}

class LobsterFactory implements GameFactory {
    @Override
    public Game createGame() {
        return new LobsterGame();
    }
}

class DotaFactory implements GameFactory {
    @Override
    public Game createGame() {
        return new DotaGame();
    }
}

class WarFactory implements GameFactory {
    @Override
    public Game createGame() {
        return new WarGame();
    }
}

Output:

Playing Lobster...
Playing Dota...
Playing War...

The factory method pattern improves clarity and extensibility. Adding a new product involves creating a new factory class. However, this increases system complexity, as each product requires a corresponding factory class.

This pattern is widely used in frameworks like Hibernate for database dialect selection. If object creation is straightforward, using this pattern may introduce unnecessary copmlexity.

Abstract Factory Pattern

The abstract factory pattern creates families of related or dependent objects without specifying their concrete classes. It provides an interface for creating families of related or dependent objects.

Compared to the factory method, the abstract factory is more complex but offers better scalability. It groups related products into families and allows clients to work with entire families of objects.

Continuing the gaming example, we can categorize games into two families: PvP (Player vs Player) and PvE (Player vs Environment):

public class GameLauncher {
    private static final String LOBSTER = "LOBSTER";
    private static final String DOTA = "DOTA";
    private static final String WAR = "WAR";

    public static void main(String[] args) {
        GameFactory factory1 = new PvPFamilyFactory();
        factory1.createGame().start();
        factory1.createGame2().start();
        
        GameFactory factory2 = new PvEFamilyFactory();
        factory2.createGame().start();
        factory2.createGame2().start();
    }
}

interface Game {
    void start();
}

class LobsterGame implements Game {
    @Override
    public void start() {
        System.out.println("Playing Lobster...");
    }
}

class DotaGame implements Game {
    @Override
    public void start() {
        System.out.println("Playing Dota...");
    }
}

class WarGame implements Game {
    @Override
    public void start() {
        System.out.println("Playing War...");
    }
}

interface GameFactory {
    Game createGame();
    Game createGame2();
}

class PvPFamilyFactory implements GameFactory {
    @Override
    public Game createGame() {
        return new LobsterGame();
    }

    @Override
    public Game createGame2() {
        return new WarGame();
    }
}

class PvEFamilyFactory implements GameFactory {
    @Override
    public Game createGame() {
        return new DotaGame();
    }

    @Override
    public Game createGame2() {
        return new WarGame();
    }
}

Output:

Playing Lobster...
Playing War...
Playing Dota...
Playing War...

With the abstract factory pattern, clients interact with families of related products without needing to know their specific implementations. While this enhances usability, it makes adding entirely new product families more challenging. Adding a new product requires implementing both new interfaces and concrete classes.

Conclusion

Each factory pattern variant addresses different aspects of object creation and system design. Choosing among them depends on the level of abstraction reqiured and the expected scope of future extensions.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.