Java implementation of the Factory Method pattern I am working on a very simple game and thought it would be a good opportunity to learn and use the Factory Method pattern for creating game objects. I studied the pattern but I'm a bit confused about the Java implementation so thought I would share what I have come up with and get some opinions. 

Please keep in mind that I am basing this design on the example from "Design Patterns... by the GOF" so we will use the following pieces: Product, ConcreteProduct, Creator, and ConcreteCreator.

Product (Interface for Game Objects)

public interface GameObject {
   public abstract void doSomeStuff();  
}


ConcreteProducts (Implements Product Interface, 1 for each Game Object)

public class PlayerImpl implements GameObject {    
    @Override
    public void doSomeStuff() {
        System.out.println("I am a player object!");
    }    
}

public class EnemyImpl implements GameObject {    
    @Override
    public void doSomeStuff() {
        System.out.println("I am an Enemy, you better run!");
    }    
}


Creator (Interface that defines how to create objects)

This is the one I'm most confused about, seems un-necessary unless instead of an Interface it was some Abstract class, but even then seems kind of pointless to use a Creator in this design pattern?

 public interface GameObjectFactory {    
    public abstract GameObject createGameObject(GameObjectFactoryImpl.Type type);    
}


ConcreteCreator (Implements Creator, creates objects)

The ConcreteCreator will have a nested enumeration to help the client decide which player types are available. We will throw an exception if for some reason there is a game object type in the enumeration that is not handled in the factory method. 

public class GameObjectFactoryImpl implements GameObjectFactory{

    // A helper enum that clients will use to create game objects
    public enum Type {
        PLAYER, ENEMY;
    }

    public GameObject createGameObject(GameObjectFactoryImpl.Type type) {

        switch (type) {    
        case PLAYER:
            return new PlayerImpl();    
        case ENEMY:
            return new EnemyImpl();    
        default:
            throw new RuntimeException("Unsupported object type!");
        }

    }
}


Client

public class Game {

    private static GameObjectFactory gameObjectFactory = new GameObjectFactoryImpl();

    public static void main(String args[]){

        GameObject player = gameObjectFactory.createGameObject(GameObjectFactoryImpl.Type.PLAYER);
        GameObject enemy = gameObjectFactory.createGameObject(GameObjectFactoryImpl.Type.ENEMY);

        player.doSomeStuff();
        enemy.doSomeStuff();
    }

}
This pattern can be difficult to understand outside of an application with many modes of operation. There are two advantages to using the factory patterns: you can swap in different implementations, and you can vary the construction parameters without changing client code.

Where do these advantages shine? Testing! In the case of a game, randomness is a good example. When playing the game for real, you want your monsters to vary their behavior randomly. But when testing, you need to be able to choose from their possible behaviors. The real factory will initialize each monster with a real random number generator, but tests must be able to specify the behavior choices. 

Take this example monster action:

public void chooseCombatAction() {
    if (isAfraid()) {
        return Action.RUN;
    }
    else {
        return Action.ATTACK;
    }
}

private boolean isAfraid() {
    return random.nextInt(10) &gt; 7;
}


To test chooseCombatAction, you need to provide a mock random number generator. But if the constructor creates it, you can't. Instead, have the factory provide it, and create an implementation that takes one with pre-configured values. Now you can give that factory to the root game object that uses the factory to create monsters.


  Style Note: Drop implied modifiers--such as public and abstract on interface members--wherever possible. Every modifier adds context that must be groked.