Fabryka jest wzorcem kreacyjnym, pozwalającym w uporządkowany sposób tworzyć różne obiekty implementujące ten sam interfejs.
Problem:
Wyobraźmy sobie, że tworzymy grę w której nasza postać musi walczyć z przeróżnymi potworami, żeby zdobywać doświadczenie.
Z doświadczenia wiemy, że takie gry mogą posiadać setki rodzajów takich przeciwników.
Jak może wyglądać kod bez użycia wzorca projektowego fabryka?
class Monster:
package monsters; public abstract class Monster { private String name; private int experience; private int hp; private int damage; private int mana; private int speed; public Monster(String name, int experience, int hp, int damage, int mana, int speed) { this.name = name; this.experience = experience; this.hp = hp; this.damage = damage; this.mana = mana; this.speed = speed; } public abstract void attack(); public abstract void walk(); public String getName() { return name; } public int getExperience() { return experience; } public int getHp() { return hp; } public int getDamage() { return damage; } public int getMana() { return mana; } public int getSpeed() { return speed; } }
class Cyclop:
package monsters; public class Cyclop extends Monster { public Cyclop(String name, int experience, int hp, int damage, int mana, int speed) { super(name, experience, hp, damage, mana, speed); } @Override public void attack() { System.out.println("Atakuję swoją maczugą"); } @Override public void walk() { System.out.println("Poruszam się z prędkością: " + getSpeed()); } }
class Demon:
package monsters; public class Demon extends Monster{ public Demon(String name, int experience, int hp, int damage, int mana, int speed) { super(name, experience, hp, damage, mana, speed); } @Override public void attack() { System.out.println("Atakuje swoimi szponami"); } @Override public void walk() { System.out.println("Poruszam się z prędkością: " + getSpeed()); } }
class Dragon:
package monsters; public class Dragon extends Monster { public Dragon(String name, int experience, int hp, int damage, int mana, int speed) { super(name, experience, hp, damage, mana, speed); } @Override public void attack() { System.out.println("Zieje ogniem"); } @Override public void walk() { System.out.println("Poruszam się z prędkością: " + getSpeed()); } }
class Minotaur:
package monsters; public class Minotaur extends Monster{ public Minotaur(String name, int experience, int hp, int damage, int mana, int speed) { super(name, experience, hp, damage, mana, speed); } @Override public void attack() { System.out.println("Atakuje swoimi rogami"); } @Override public void walk() { System.out.println("Poruszam się z prędkością: " + getSpeed()); } }
class Skeleton:
package monsters; public class Skeleton extends Monster{ public Skeleton(String name, int experience, int hp, int damage, int mana, int speed) { super(name, experience, hp, damage, mana, speed); } @Override public void attack() { System.out.println("Atakuje swoimi czarami"); } @Override public void walk() { System.out.println("Poruszam się z prędkością: " + getSpeed()); } }
class Zombie:
package monsters; public class Zombie extends Monster{ public Zombie(String name, int experience, int hp, int damage, int mana, int speed) { super(name, experience, hp, damage, mana, speed); } @Override public void attack() { System.out.println("Zjadam mózgi"); } @Override public void walk() { System.out.println("Poruszam się z prędkością: " + getSpeed()); } }
class Main:
import monsters.*; public class Main { public static void main(String[] args) { Monster skeleton = new Skeleton("Szkieletor", 0, 100, 20,10,5); Monster demon = new Demon("Demon", 0, 300, 50,30,15); Monster dragon = new Dragon("Smok", 0, 200, 40,20,15); Monster zombie = new Zombie("Zombie", 0, 80, 20,0,5); Monster minotaur = new Minotaur("Minotaur", 0, 90, 30,0,10); Monster cyclop = new Cyclop("Cyklop", 0, 120, 30,20,20); } }
A teraz wyobraź sobie, że musisz tworzyć w dalszej części kodu jeszcze kilkanaście takich potworów, pamiętając za każdym razem jakie statystki posiada każdy z nich. Problematyczne prawda? Z pomocą przychodzi nam wzorzec Fabryka,
który pomoże nam w prosty sposób utworzyć nowe obiekty przez nas bez użycia operatora „new”. Nie będziemy musieli martwić się na przykład o to czy stworzony przez nas kolejny „Szkieletor” nie okaże się siliniejszy od „Demona”.
Rozwiązanie (pominę tutaj kod który nie został zmieniony przy implementacji wzorca):

interface Factory:
package monsters; public interface Factory { Monster createMonster(MonsterType monsterType); }
enum MonsterType:
package monsters; public enum MonsterType { CYCLOP, DEMON, DRAGON, MINOTAUR, SKELETON, ZOMBIE }
class MonsterFactory:
package monsters; public class MonsterFactory implements Factory{ @Override public Monster createMonster(MonsterType monsterType) { switch(monsterType){ case CYCLOP: return new Cyclop("Cyklop", 0, 120, 30,20,20); case DEMON: return new Demon("Demon", 0, 300, 50,30,15); case DRAGON: return new Dragon("Smok", 0, 200, 40,20,15); case MINOTAUR: return new Minotaur("Minotaur", 0, 90, 30,0,10); case SKELETON: return new Skeleton("Szkieletor", 0, 100, 20,10,5); case ZOMBIE: return new Zombie("Zombie", 0, 80, 20,0,5); default: throw new UnsupportedOperationException("Wybrałeś nieprawidłową klasę potwora"); } } }
class Main:
import monsters.*; public class Main { public static void main(String[] args) { Factory monsterFactory = new MonsterFactory(); Monster skeleton = monsterFactory.createMonster(MonsterType.SKELETON); Monster cyclop = monsterFactory.createMonster(MonsterType.CYCLOP); Monster demon = monsterFactory.createMonster(MonsterType.DEMON); } }
Jak widzisz wzorzec Fabryka a dokładniej metoda wytwórcza należy raczej do prostszych w implementacji wzorców. U nas widoczne zmiany to dodanie interfejsu „Factory” w którym tworzymy metodę „createMonster”, która przyjmuję enum „MonsterType”. Dodajemy również klasę właściwej fabryki „MonsterFactory” która implementuje nasz interfejs „Factory” i nadpisuje jej metodę. Jeśli chodzi o samo tworzenie obiektu w metodzie „createMonster” to w naszym przykładzie używamy warunku wielokrotnego wyboru, ale równie dobrze mogłaby być to instrukcja warunkowa if.
Mam nadzieję, że pomogłem Ci zrozumieć wzorzec projektowy Fabryka.