Search code examples
factory-patterndesign-patterns

What's the right way to use the Factory method design pattern?


enter image description here

The diagram above taken from the factory method example, the cross at the right corner indicate it's not the right solution. So I came up with my own:

Runner.java

package test;

public class Runner {

    /**
     * @param args
     */
    public static void main(String[] args) {
        Fighter f = new Fighter();
        f.attack();
        Wizard w = new Wizard();
        w.attack();
    }

}

Player.java

package test;

public abstract class Player {
    protected String type;

    public Player(String type) {
        this.type = type;
    }
    public void attack() {
        WeaponFactory.getWeapon(type).hit();
    }
}

Fighter.java

package test;

public class Fighter extends Player {

    public Fighter() {
        super("Fighter");
    }

}

Wizard.java

package test;

public class Sword implements Weapon {

    public Sword() {
    }

    public void hit() {
        System.out.println("Hit by sword");
    }

}

Weapon.java

package test;

public abstract class Weapon {

    public void hit(){};

}

Wand.java

package test;

public class Wand extends Weapon {

    public Wand() {
    }

    public void hit() {
        System.out.println("Hit by Wand");
    }

}

Sword.java

package test;

public class Sword extends Weapon {

    public Sword() {
    }

    public void hit() {
        System.out.println("Hit by sword");
    }

}

WeaponFactory.java

package test;

public class WeaponFactory {


    public static Weapon getWeapon(String type) {
        Weapon returnValue = null;
        if(type.equals("Wizard")) {
            returnValue = new Wand();
        }else if(type.equals("Fighter")) {
            returnValue = new Sword();
        }
        return returnValue;
    }

}

Did I do it right in term of using the Factory method design pattern


Solution

  • Your WeaponFactory violates the Open-Closed Principle. To be compliant with object oriented design, consider following changes:

    public abstract class Player {
        protected WeaponFactory weaponFactory;
    
        public Player(WeaponFactory weaponFactory) {
            this.weaponFactory = weaponFactory;
        }
        public void attack() {
            weaponFactory.getWeapon().hit();
        }
    }
    
    public class Fighter extends Player {
        public Fighter() {
            super(new SwordFactory());
        }
    }
    
    public interface WeaponFactory {
        Weapon getWeapon();
    }
    

    Create SwordFactory and WandFactory implementing WeaponFactory.