Factory Method pattern – Tworzenie obiektów w elegancki sposób

TL;DR: Factory Method to wzorzec projektowy, który pozwala tworzyć obiekty bez określania konkretnej klasy. Zamiast „new SomeClass()” używasz metody fabryki, która decyduje jaki obiekt utworzyć. Idealne rozwiązanie gdy nie wiesz z góry jakiego typu obiekt będziesz potrzebować.

Dlaczego Factory Method jest ważny

Każdy programista Java musi regularnie tworzyć obiekty. Zazwyczaj robisz to przez new Object(), ale co gdy masz kilka podobnych klas i chcesz wybrać właściwą w zależności od sytuacji? Factory Method rozwiązuje ten problem elegancko – działa jak „fabryka” która produkuje właściwy obiekt na zamówienie.

Co się nauczysz:

  • Czym jest wzorzec Factory Method i kiedy go używać
  • Różnicę między Factory Method a zwykłym konstruktorem
  • Jak implementować Factory Method w praktyce
  • Praktyczne przykłady z życia codziennego programisty
  • Najczęstsze błędy i jak ich unikać
Wymagania wstępne: Podstawowa znajomość Java, inheritance, interfaces i tworzenia obiektów przez konstruktory.

Analogia ze świata rzeczywistego

Factory Method to jak zamówienie w restauracji fast-food. Mówisz „poproszę burger” (wywołujesz metodę fabryki), a kucharz decyduje czy zrobić wołowego, drobiowego czy wegetariańskiego w zależności od dostępnych składników. Ty nie musisz wiedzieć jak się robi konkretny burger – dostajesz gotowy produkt.

Podstawowa implementacja Factory Method

Zacznijmy od prostego przykładu z systemem płatności:

// Interfejs produktu
public interface PaymentProcessor {
    void processPayment(double amount);
}

// Konkretne implementacje
public class CreditCardProcessor implements PaymentProcessor {
    @Override
    public void processPayment(double amount) {
        System.out.println("Processing $" + amount + " via Credit Card");
        // logika płatności kartą
    }
}

public class PayPalProcessor implements PaymentProcessor {
    @Override
    public void processPayment(double amount) {
        System.out.println("Processing $" + amount + " via PayPal");
        // logika płatności PayPal
    }
}

public class BankTransferProcessor implements PaymentProcessor {
    @Override
    public void processPayment(double amount) {
        System.out.println("Processing $" + amount + " via Bank Transfer");
        // logika przelewu bankowego
    }
}

Teraz tworzymy fabrykę:

public class PaymentProcessorFactory {
    
    public static PaymentProcessor createProcessor(String type) {
        switch (type.toLowerCase()) {
            case "creditcard":
                return new CreditCardProcessor();
            case "paypal":
                return new PayPalProcessor();
            case "banktransfer":
                return new BankTransferProcessor();
            default:
                throw new IllegalArgumentException("Unknown payment type: " + type);
        }
    }
}
Factory Method – metoda która tworzy obiekty bez określania dokładnej klasy obiektu. Klient wie jakiego typu obiekt chce („payment processor”), ale nie musi wiedzieć konkretnej implementacji.

Użycie Factory Method w praktyce

public class ShoppingCart {
    
    public void checkout(String paymentMethod, double totalAmount) {
        // Tworzymy odpowiedni procesor płatności
        PaymentProcessor processor = PaymentProcessorFactory.createProcessor(paymentMethod);
        
        // Używamy bez wiedzy o konkretnej implementacji
        processor.processPayment(totalAmount);
        
        System.out.println("Order completed successfully!");
    }
}

// Użycie
public class Main {
    public static void main(String[] args) {
        ShoppingCart cart = new ShoppingCart();
        
        cart.checkout("creditcard", 99.99);  // Użyje CreditCardProcessor
        cart.checkout("paypal", 49.99);      // Użyje PayPalProcessor
        cart.checkout("banktransfer", 199.99); // Użyje BankTransferProcessor
    }
}

Zauważ, że metoda checkout() nie musi wiedzieć jaką konkretną klasę tworzy. Po prostu żąda „payment processor” i używa go przez interfejs.

Zalety Factory Method

Pro tip: Factory Method świetnie sprawdza się gdy dodajesz nowe typy obiektów. Wystarczy stworzyć nową klasę i dodać ją do fabryki – reszta kodu pozostaje nietknięta.

**Główne korzyści:**
– **Elastyczność:** Łatwo dodawać nowe typy bez zmiany istniejącego kodu
– **Enkapsulacja:** Logika tworzenia obiektów jest w jednym miejscu
– **Testowanie:** Można łatwo podmienić implementacje w testach
– **Czytelność:** Kod jasno pokazuje intencję („stwórz payment processor”)

Rozszerzona wersja z enum

public enum PaymentType {
    CREDIT_CARD,
    PAYPAL,
    BANK_TRANSFER
}

public class ImprovedPaymentFactory {
    
    public static PaymentProcessor createProcessor(PaymentType type) {
        switch (type) {
            case CREDIT_CARD:
                return new CreditCardProcessor();
            case PAYPAL:
                return new PayPalProcessor();
            case BANK_TRANSFER:
                return new BankTransferProcessor();
            default:
                throw new IllegalArgumentException("Unsupported payment type: " + type);
        }
    }
}
Uwaga: Używanie enum zamiast String jest bezpieczniejsze – kompilator sprawdzi czy używasz poprawnych wartości.

Najczęstsze błędy początkujących

Typowy błąd: Tworzenie zbyt skomplikowanych fabryk. Jeśli masz tylko 1-2 klasy, zwykły konstruktor może być lepszym rozwiązaniem.
Pułapka: Zapominanie o obsłudze nieznanych typów. Zawsze dodaj default case w switch lub rzuć wyjątek dla nieobsługiwanych wartości.

Kiedy NIE używać Factory Method

Factory Method może być przesadą gdy:
– Masz tylko jedną klasę do tworzenia
– Logika tworzenia jest bardzo prosta
– Nie przewidujesz dodawania nowych typów

**Alternatywy:**
– Zwykły konstruktor dla prostych przypadków
– Builder pattern dla obiektów z wieloma parametrami
– Dependency Injection w większych aplikacjach

Czym różni się Factory Method od zwykłego konstruktora?

Konstruktor tworzy konkretny obiekt określonej klasy. Factory Method może zwrócić różne obiekty w zależności od parametrów, ale wszystkie implementują ten sam interfejs.

Czy Factory Method to to samo co Abstract Factory?

Nie. Factory Method to jedna metoda tworząca obiekty jednego typu. Abstract Factory to interfejs do tworzenia rodzin powiązanych obiektów.

Kiedy powinienem używać Factory Method?

Gdy masz kilka klas implementujących ten sam interfejs i chcesz wybrać właściwą w runtime na podstawie parametrów.

Czy Factory Method może zwracać null?

Technicznie tak, ale lepiej rzucić wyjątek lub zwrócić domyślną implementację. Null prowadzi do NullPointerException.

Jak testować kod używający Factory Method?

Możesz stworzyć testową implementację fabryki zwracającą mock obiekty, lub przetestować każdy typ produktu osobno.

Przydatne zasoby

🚀 Zadanie dla Ciebie

Stwórz Factory Method dla różnych typów loggerów (ConsoleLogger, FileLogger, DatabaseLogger). Każdy logger powinien implementować interfejs Logger z metodą log(String message). Przetestuj fabrykę tworząc różne typy loggerów i używając ich do zapisywania wiadomości.

Gdzie jeszcze widzisz zastosowanie dla Factory Method w swoich projektach? Podziel się pomysłami w komentarzach!

Zostaw komentarz

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

Przewijanie do góry