new, welche konkrete Klasse erzeugt wird, sondern fragt die Factory danachEin Bezahlsystem soll eine Zahlung abwickeln können, je nachdem, welche Zahlungsmethode der Kunde wählt: PayPal, Kreditkarte oder Überweisung.
Naive Lösung – ohne Factory Pattern:
public class Main {
public static void main(String[] args) {
String methode = "paypal"; // stammt z. B. aus der Nutzerauswahl im Checkout
if (methode.equals("paypal")) {
PayPalZahlung zahlung = new PayPalZahlung();
zahlung.bezahlen(49.99);
} else if (methode.equals("kreditkarte")) {
KreditkartenZahlung zahlung = new KreditkartenZahlung();
zahlung.bezahlen(49.99);
} else if (methode.equals("ueberweisung")) {
UeberweisungsZahlung zahlung = new UeberweisungsZahlung();
zahlung.bezahlen(49.99);
}
}
}
Ausgabe:
Zahlung über PayPal: 49.99€ + 1.80€ Gebühr = 51.79€ abgebucht.
Problem damit:
main kennt alle drei konkreten Zahlungsklassen direktmain enthält die komplette Verzweigungslogik (if/else)main – und an jeder anderen Stelle im Programm, die ebenfalls Zahlungen erzeugtmain) und konkrete Zahlungsklassen sind eng gekoppeltZahlungsFactory übernimmt die Entscheidung, welche konkrete Zahlungsklasse erzeugt wirdmain fragt nur noch die Factory nach einer Zahlung und kennt keine konkrete Klasse mehrZahlung, damit main sie austauschbar behandeln kannif/else oder switch) und das einzige new je konkreter Klasse – nirgendwo sonst im ProgrammLosgelöst von der Zahlung-Geschichte bleibt als abstrakte Schablone:
interface Produkt { void aktion(); }
class ProduktA implements Produkt { public void aktion() { /* ... */ } }
class ProduktB implements Produkt { public void aktion() { /* ... */ } }
class ProduktFactory {
public static Produkt create(String typ) {
if (typ.equals("a")) return new ProduktA();
if (typ.equals("b")) return new ProduktB();
throw new IllegalArgumentException("Unbekannter Typ: " + typ);
}
}
Der Client benutzt ausschließlich Produkt und ProduktFactory.create(typ) – nie new ProduktA() oder new ProduktB() direkt. Alles andere (Zahlung/PayPal/Kreditkarte, Versand/Standard/Express, Benachrichtigung/E-Mail/SMS …) ist nur austauschbares Vokabular über dieser Struktur.
Zahlung (Interface)
bezahlen(double betrag), die jede konkrete Zahlungsart implementieren mussPayPalZahlung, KreditkartenZahlung, UeberweisungsZahlung (konkrete Klassen)
Zahlung und berechnen jeweils ihre eigene Gebühr auf den übergebenen Betrag, bevor sie den Endbetrag ausgebenZahlungsFactory
create(String methode)Zahlung-Implementierung erzeugt wirdnew PayPalZahlung(), new KreditkartenZahlung() bzw. new UeberweisungsZahlung() stehtMain)
ZahlungsFactory.create(methode) aufZahlung-Schnittstelle weiterpublic interface Zahlung {
void bezahlen(double betrag);
}
public class PayPalZahlung implements Zahlung {
public void bezahlen(double betrag) {
double gebuehr = betrag * 0.029 + 0.35;
double endbetrag = betrag + gebuehr;
System.out.printf("Zahlung über PayPal: %.2f€ + %.2f€ Gebühr = %.2f€ abgebucht.%n", betrag, gebuehr, endbetrag);
}
}
public class KreditkartenZahlung implements Zahlung {
public void bezahlen(double betrag) {
double gebuehr = betrag * 0.015;
double endbetrag = betrag + gebuehr;
System.out.printf("Zahlung per Kreditkarte: %.2f€ + %.2f€ Gebühr = %.2f€ abgebucht.%n", betrag, gebuehr, endbetrag);
}
}
public class UeberweisungsZahlung implements Zahlung {
public void bezahlen(double betrag) {
System.out.printf("Zahlung per Überweisung: %.2f€ ohne Gebühr abgebucht.%n", betrag);
}
}
public class ZahlungsFactory {
public static Zahlung create(String methode) {
if (methode.equals("paypal")) return new PayPalZahlung();
if (methode.equals("kreditkarte")) return new KreditkartenZahlung();
if (methode.equals("ueberweisung")) return new UeberweisungsZahlung();
throw new IllegalArgumentException("Unbekannte Zahlungsmethode: " + methode);
}
}
public class Main {
public static void main(String[] args) {
Zahlung paypal = ZahlungsFactory.create("paypal");
paypal.bezahlen(49.99);
Zahlung kreditkarte = ZahlungsFactory.create("kreditkarte");
kreditkarte.bezahlen(49.99);
Zahlung ueberweisung = ZahlungsFactory.create("ueberweisung");
ueberweisung.bezahlen(49.99);
}
}
Ausgabe:
Zahlung über PayPal: 49.99€ + 1.80€ Gebühr = 51.79€ abgebucht.
Zahlung per Kreditkarte: 49.99€ + 0.75€ Gebühr = 50.74€ abgebucht.
Zahlung per Überweisung: 49.99€ ohne Gebühr abgebucht.
main kennt nur noch Zahlung und ZahlungsFactory – keine der drei konkreten Klassen wird hier importiert oder direkt instanziiert. Das einzige new für Zahlungsobjekte steht in ZahlungsFactory. Und weil jede Zahlungsart ihre eigene Gebührenlogik in bezahlen() kapselt, erzeugt derselbe Ausgangsbetrag (49.99€) bei jeder Zahlart einen anderen, tatsächlich abgebuchten Endbetrag.
Vorteile:
Nachteile:
create-Methode zu einer langen, unübersichtlichen if/else-Kette