Fabryka Factory

Do czego służy Fabryka?
Jest to kreacyjny wzorzec projektowy. Wyróżniamy dwie odmiany tego wzorca: Metoda Fabrykująca oraz Fabryka Abstrakcyjna. Obydwie odmiany mają ten sam cel: uprościć tworzenie nowych obiektów. Na początku zamieściłem przykład, który jeszcze nie używa wzorca Fabryka, zobaczmy jakie problemy napotykamy. Uważam, że dobrym przykładem będzie po prostu gra w statki.
Kodowanie gry w statki bez używania Fabryki
Na początku tworzymy klasę Ship, która zawiera prywatne cechy, które otrzyma każdy obiekt po utworzeniu. W naszym przykładzie cechę „rozmiar” otrzyma każdy statek. W klasie Ship tworzymy też konstruktor i getter.
Następnie tworzymy klasy statków czteromasztowych ShipSizeFour, trzymasztowych ShipSizeThree, itd. One dziedziczą po klasie Ship.
W klasie main tworzymy obiekty (statki).
public class Main {
public static void main(String[] args) {
Ship shipSizeFour = new Ship(4);
Ship shipSizeThree = new Ship(3);
}
}
public class Ship {
private int size;
public Ship(int size) {
this.size = size;
}
public int getSize() {
return size;
}
}
public class ShipSizeFour extends Ship {
public ShipSizeFour(int size) {
super(size);
}
}
public class ShipSizeThree extends Ship {
public ShipSizeThree(int size) {
super(size);
}
}
Możliwe ryzyka i ich eliminowanie
Podczas tworzenia nowych obiektów może w łatwy sposób dojść do pomyłek, dlatego też wymyślono wzorzec Fabryka. Fabryka polega na oddelegowaniu tworzenia nowych obiektów do innych klas, tak by użytkownik musiał tylko zawołać jedną metodę i już otrzymał gotowy obiekt.
Fabryka - schemat działania

W moim artykule zaprezentuję odmianę Metoda Fabrykująca W tej odmianie można wyróżnić 4 główne elementy:
- 1. Fabryka abstrakcyjna, która rozszerza Fabrykę właściwą.
- 2. Fabryka właściwa, która tworzy okręty.
- 3. Okręty: czteromasztowce, trójmasztowce, itd.
- 4. Klasa abstrakcyjna okrętów.
Poniżej można zapoznać się z gotowym kodem, w którym zaimplementowano wzorzec Fabryka.
public class Main {
public static void main(String[] args) {
Factory factory = new ShipFactory();
Ship shipSizeFour = factory.createShip(ShipType.SHIP_SIZE_FOUR);
Ship shipSizeThree = factory.createShip(ShipType.SHIP_SIZE_THREE);
Ship shipSizeTwo = factory.createShip(ShipType.SHIP_SIZE_TWO);
Ship shipSizeOne = factory.createShip(ShipType.SHIP_SIZE_ONE);
}
}
public class Ship {
private int size;
protected Ship(int size) {
this.size = size;
}
public int getSize() {
return size;
}
}
public class ShipSizeFour extends Ship {
ShipSizeFour(int size) {
super(size);
}
}
public class ShipSizeThree extends Ship {
ShipSizeThree(int size) {
super(size);
}
}
public class ShipFactory extends Factory{
@Override
public Ship createShip(ShipType type) {
switch(type) {
case SHIP_SIZE_FOUR -> {
return new ShipSizeFour(4);
}
case SHIP_SIZE_THREE -> {
return new ShipSizeThree(3);
}
case SHIP_SIZE_TWO -> {
return new ShipSizeTwo(2);
}
case SHIP_SIZE_ONE -> {
return new ShipSizeOne(1);
}
default -> {
throw new UnsupportedOperationException(„No such type”);
}
}
}
abstract public Ship createShip(ShipType type);
}
public enum ShipType {
SHIP_SIZE_FOUR, SHIP_SIZE_THREE, SHIP_SIZE_TWO, SHIP_SIZE_ONE
}
Podsumowanie
Utworzyliśmy nowe statki za pomocą fabryki. Trzeba też pamiętać, aby konstruktor klasy Ship nie był dostępny w klasie main, dlatego warto nadać mu operator dostępu protected i wszystkie klasy dotyczące tworzenia statków przenieść do osobnego folderu.
Podsumowując, wzorzec fabryka jest bardzo pomocny do tworzenia obiektów. Użytkownik, który tworzy obiekty, nie musi wiedzieć jak one się tworzą, jakie mają parametry. Obiekty, które tworzymy stosując fabrykę są ze sobą kompatybilne.
