Wzorzec projektowy Fabryka – opis i przykład zastosowania

Problem do rozwiązania:

  1. Potrzebujemy uprościć tworzenie nowych obiektów.
  2. 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:

  1. Poprzez metodę fabrykującą (jeden typ produktów i jedna fabryka, fabryka produkuje jeden typ produktu);
  2. 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:

  1. Tworzymy obiekt klasy UnitFactory(), rozszerzającej klasę Factory (a więc typu Factory).
  2. Klasa Factory jest abstrakcyjna, zawiera deklarację metody:
    • Unit createUnit(UnitType type)
  3. 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ć.
  4. 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:

  1. 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ć.
  2. 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:

 

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *