Problem do rozwiązania:
- Potrzebujemy uprościć tworzenie nowych obiektów.
- Chcemy oddelegować tworzenie nowych obiektów do innych klas, by po wywołaniu jednej metody użytkownik otrzymał gotowy obiekt (nie chcemy korzystać w klasie głównej z konstruktora).
Opis wzorca Fabryka:
Wzorzec ten możemy zaimplementować na dwa sposoby:
- Poprzez metodę fabrykującą (jeden typ produktów i jedna fabryka, fabryka produkuje jeden typ produktu);
- Poprzez fabrykę abstrakcyjną (dla więcej niż jednego typu produktów i większej ilości fabryk, fabryka produkuje obiekty różnych typów);
Schemat UML rozwiązania metodą fabrykującą:

Schemat działania:
W programie mamy 2 klasy abstrakcyjne: Unit i Factory. Jedna jest przypisana do naszych produktów, które będą ją rozszerzać, zaś druga służy jako szablon do budowy fabryki (czasami jest pomijana).
Schemat postępowania w klasie main:
- Tworzymy obiekt klasy UnitFactory(), rozszerzającej klasę Factory (a więc typu Factory).
- Klasa Factory jest abstrakcyjna, zawiera deklarację metody:
- Unit createUnit(UnitType type)
- W klasie UnitFactory nadpisujemy już konkretną implementacją metodę createUnit() w zależności od typu, który będziemy produkować w naszej fabryce. Każdemu z typów przekazujemy w konstruktorze parametry, jakie mają go charakteryzować.
- Tworzymy obiekty typu Unit poprzez wywołanie na utworzonym obiekcie fabryki metody createUnit(), gdzie jako argument przekazujemy typ UnitType (korzystamy z faktu, że klasy Tank i Rifleman rozszerzają klasę abstrakcyjną Unit, a więc są jednego typu Unit).
Fragment klasy main:
Factory factory = new UnitFactory();
Unit tank = factory.createUnit(UnitType.TANK);
Unit infantryman = factory.createUnit(UnitType.RIFLEMAN);
Schemat UML rozwiązania z fabryką abstrakcyjną:

Schemat działania:
W programie mamy 3 klasy abstrakcyjne: InfantryUnit, MechanizedUnit i Factory. Pierwsza jest przypisana do jednostek piechoty, druga do czołgów, zaś trzecia służy jako szablon do budowy fabryki (w naszym przypadku dwóch fabryk tj. BlueFactory i RedFactory).
Schemat postępowania w klasie main:
- Tworzymy obiekty klas BlueFactory i RedFactory, rozszerzających klasę Factory (a więc typu Factory).
- Klasa Factory jest abstrakcyjna, zawiera deklarację metod zwracających 3 różne typy:
- InfantryUnit createInfantryUnit(UnitType type)
- MechanizedUnit createMechanizedUnit (UnitType type)
- AirUnit createAirUnit (UnitType type)
- W klasach BlueFactory i RedFactory nadpisujemy już konkretnymi implementacjami powyższe metody. Każdemu z typów przekazujemy w konstruktorze parametry, jakie mają go charakteryzować.
- Klasa Factory jest abstrakcyjna, zawiera deklarację metod zwracających 3 różne typy:
- Tworzymy obiekty typu MechanizedUnit, InfantryUnit, AirUnit poprzez wywołanie na utworzonych obiektach fabryk metod createInfantryUnit(), createMechanizedUnit(), createAirUnit(), gdzie jako argument przekazujemy odpowiedni typ.
Fragment klasy main:
Factory blueFactory = new BlueFactory();
Factory redFactory = new RedFactory();
MechanizedUnit redTank = redFactory.createMechanizedUnit(UnitType.TANK);
InfantryUnit redInfantryman = redFactory.createInfantryUnit(UnitType.RIFLEMAN);
MechanizedUnit blueTank = blueFactory.createMechanizedUnit(UnitType.TANK);
InfantryUnit blueInfantryman = blueFactory.createInfantryUnit(UnitType.RIFLEMAN);
AirUnit blueHelicopter = blueFactory.createAirUnit(UnitType.HELICOPTER);
AirUnit redHelicopter = redFactory.createAirUnit(UnitType.HELICOPTER);
Kod programu przed zastosowaniem wzorca:
Klasa main:
public class Main {
public static void main(String[] args) {
Unit tank = new Tank(200,0,20);
Unit infantryman = new Rifleman(100,0,10);
}
}
Klasa Unit:
public abstract class Unit {
private int hp;
private int exp;
private int dmgDone;
public Unit(int hp, int exp, int dmgDone) {
this.hp = hp;
this.exp = exp;
this.dmgDone = dmgDone;
}
public int getHp() {
return hp;
}
public int getExp() {
return exp;
}
public int getDmgDone() {
return dmgDone;
}
}
Klasa Tank:
public class Tank extends Unit{
public Tank(int hp, int exp, int dmgDone) {
super(hp, exp, dmgDone);
}
}
Klasa Rifleman:
public class Rifleman extends Unit {
public Rifleman(int hp, int exp, int dmgDone) {
super(hp, exp, dmgDone);
}
}
Kod programu po zastosowaniu wzorca z metodą fabrykującą:
Klasa main:
import units.*;
public class Main {
public static void main(String[] args) {
Factory factory = new UnitFactory();
Unit tank = factory.createUnit(UnitType.TANK);
Unit infantryman = factory.createUnit(UnitType.RIFLEMAN);
}
}
Klasa Factory:
package units;
abstract public class Factory {
abstract public Unit createUnit(UnitType type);
}
Klasa UnitFactory:
package units;
public class UnitFactory extends Factory {
@Override
public Unit createUnit(UnitType unitType) {
switch (unitType){
case TANK:
return new Tank(200,0,20);
case RIFLEMAN:
return new Rifleman(100,0,10);
default:
throw new UnsupportedOperationException("No such type");
}
}
}
Klasa Unit:
package units;
abstract public class Unit {
private int hp;
private int exp;
private int dmgDone;
protected Unit(int hp, int exp, int dmgDone) {
this.hp = hp;
this.exp = exp;
this.dmgDone = dmgDone;
}
public int getHp() {
return hp;
}
public int getExp() {
return exp;
}
public int getDmgDone() {
return dmgDone;
}
}
Klasa UnitType:
package units;
public enum UnitType {
RIFLEMAN, TANK
}
Klasa Tank:
package units;
public class Tank extends Unit {
Tank(int hp, int exp, int dmgDone) {
super(hp, exp, dmgDone);
}
}
Klasa Rifleman:
package units;
public class Rifleman extends Unit {
Rifleman(int hp, int exp, int dmgDone) {
super(hp, exp, dmgDone);
}
}
Kod programu po zastosowaniu wzorca z fabryką abstrakcyjną:
Klasa main:
import units.*;
public class Main {
public static void main(String[] args) {
Factory blueFactory = new BlueFactory();
Factory redFactory = new RedFactory();
MechanizedUnit redTank = redFactory.createMechanizedUnit(UnitType.TANK);
InfantryUnit redInfantryman = redFactory.createInfantryUnit(UnitType.RIFLEMAN);
MechanizedUnit blueTank = blueFactory.createMechanizedUnit(UnitType.TANK);
InfantryUnit blueInfantryman = blueFactory.createInfantryUnit(UnitType.RIFLEMAN);
AirUnit blueHelicopter = blueFactory.createAirUnit(UnitType.HELICOPTER);
AirUnit redHelicopter = redFactory.createAirUnit(UnitType.HELICOPTER);
}
}
Klasa Factory:
Klasa BlueFactory:
Klasa RedFactory:
Klasa UnitType:
Klasa InfantryUnit:
Klasa MechanizedUnit:
Klasa Rifleman:
Klasa Tank:
Klasa Helicopter:
