Factory-Muster
Teil des Abschnitts Objektorientierte Programmierung der Java-Journey von Coddy. Lektion 66 von 87.
Das Factory Pattern ist ein erzeugendes Entwurfsmuster, das die Objekterstellung an eine separate Methode oder Klasse delegiert. Anstatt new direkt in deinem Code zu verwenden, bittest du eine Factory, Objekte für dich zu erstellen. Das ist besonders nützlich, wenn du mehrere verwandte Klassen hast, die eine gemeinsame Schnittstelle oder Basisklasse verwenden.
Betrachten Sie ein Benachrichtigungssystem, das E-Mails, SMS oder Push-Benachrichtigungen senden kann. Ohne eine Factory müsste Ihr Code jede konkrete Klasse kennen:
// Ohne Factory - Client muss alle konkreten Klassen kennen
Notification notification;
if (type.equals("email")) {
notification = new EmailNotification();
} else if (type.equals("sms")) {
notification = new SMSNotification();
}Mit dem Factory Pattern zentralisierst du diese Erstellungslogik:
public interface Notification {
void send(String message);
}
public class EmailNotification implements Notification {
public void send(String message) {
System.out.println("Email: " + message);
}
}
public class SMSNotification implements Notification {
public void send(String message) {
System.out.println("SMS: " + message);
}
}
public class NotificationFactory {
public static Notification create(String type) {
if (type.equals("email")) {
return new EmailNotification();
} else if (type.equals("sms")) {
return new SMSNotification();
}
return null;
}
}Jetzt ist der Client-Code übersichtlicher und hängt nicht von konkreten Klassen ab:
Notification notification = NotificationFactory.create("email");
notification.send("Hello!"); // Ausgabe: Email: Hello!Der wesentliche Vorteil besteht darin, dass das Hinzufügen neuer Benachrichtigungstypen nur eine Aktualisierung der Factory erfordert: Der Client-Code bleibt unverändert. Dies folgt dem Prinzip, gegen ein Interface zu programmieren, wodurch dein System flexibler und leichter erweiterbar wird.
Aufgabe
EinfachLass uns ein System zum Zeichnen von Formen mit dem Factory Pattern erstellen! Anstatt überall in deinem Code direkt Formobjekte zu erstellen, zentralisierst du die Erstellungslogik in einer Factory, die anhand eines einfachen String-Bezeichners verschiedene Formtypen erzeugt.
Du organisierst deinen Code auf vier Dateien:
Shape.java: Definiere ein Interface namensShape, das als gemeinsamer Vertrag für alle Formen dient. Dein Interface sollte eine einzelne Methodedraw()deklarieren, die nichts zurückgibt, sondern Informationen über die gezeichnete Form ausgibt.Shapes.java: Erstelle drei Klassen, die deinShape-Interface implementieren:Circle– die Methodedraw()sollDrawing a CircleausgebenRectangle– die Methodedraw()sollDrawing a RectangleausgebenTriangle– die Methodedraw()sollDrawing a TriangleausgebenShapeFactory.java: Erstelle die Factory-Klasse, die die Formerstellung übernimmt. DeineShapeFactorysollte eine statische MethodecreateShape(String type)besitzen, die einShapezurückgibt. Abhängig vom Parameter type gilt:- Wenn type gleich
"circle"ist, gib ein neuesCirclezurück - Wenn type gleich
"rectangle"ist, gib ein neuesRectanglezurück - Wenn type gleich
"triangle"ist, gib ein neuesTrianglezurück - Für jeden anderen Wert gib
nullzurück
- Wenn type gleich
Main.java: Führe dein Factory-System zusammen! Du erhältst zwei Eingaben: zwei Formtypen (beide Strings).Verwende für jede Eingabe deine
ShapeFactory, um die Form zu erstellen, und speichere sie in einerShape-Variable. Wenn die Factory eine gültige Form zurückgibt (nicht null), rufe ihre Methodedraw()auf. Wenn sie null zurückgibt, gibUnknown shape: [type]aus, wobei [type] die bereitgestellte Eingabe ist.Verarbeite beide Eingaben in der angegebenen Reihenfolge, jeweils in einer eigenen Ausgabezeile.
Du erhältst zwei Eingaben in dieser Reihenfolge: den ersten Formtyp (String) und den zweiten Formtyp (String).
Beachte, dass deine Main-Klasse niemals direkt new Circle() oder new Rectangle() verwendet. Sie kennt nur das Shape-Interface und bittet die Factory, Objekte zu erstellen. Das ist die Stärke des Factory Pattern: Der Client-Code ist von den konkreten Klassen entkoppelt!
Probier es selbst
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Zwei Formtypen einlesen
String type1 = scanner.nextLine();
String type2 = scanner.nextLine();
// TODO: ShapeFactory verwenden, um die erste Form zu erstellen
// Wenn die Form nicht null ist, draw() aufrufen
// If the shape is null, print "Unknown shape: [type]"
// TODO: Dasselbe für die zweite Form tun
}
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDas Schlüsselwort thisMethodenFelder (Attribute)KonstruktormethodeÜberladen von KonstruktorenRückblick – Einfacher Taschenrechner4Vererbung
Grundlegende Vererbung (extends)Das Schlüsselwort superÜberschreiben von Methoden (@Override)KonstruktorverkettungDie Object-KlasseEinfach- und mehrstufige VererbungWarum keine Mehrfachvererbung von KlassenRückblick – Mitarbeiterhierarchie7Spezielle Methoden & Object-Klasse
toString()-Methodeequals() und hashCode()clone()-MethodecompareTo() und ComparableComparator-SchnittstelleRückblick – Benutzerdefinierte Sortierung2Zugriffsmodifikatoren & Kapselung
Übersicht der ZugriffsebenenGetter- und Setter-MethodenInformationsverbergungDas Schlüsselwort finalRückblick – Bankkontoverwaltung5Polymorphismus
Grundlagen der MethodenüberladungMethodenüberschreibung (Laufzeit)Upcasting und DowncastingDer instanceof-OperatorAbstrakte Klassen und MethodenRückblick – Formrechner8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungAggregation vs. KompositionInnere, verschachtelte & anonyme KlassenEnums und Enum-MethodenRecords (Java 16+)Versiegelte Klassen (Java 17+)11Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterBuilder-MusterObserver-MusterStrategie-Muster14Abschließende Herausforderungen
E-Learning-PlattformBankingsystemEntwicklung einer SpielfigurFahrzeugvermietungsdienst3Klassen-Props & statische Member
Instanz- vs. statische VariablenStatische MethodenStatische BlöckeKonstanten (static final)Wiederholung – Counter & Utility6Schnittstellen & abstrakte Klassen
Einführung in InterfacesInterfaces implementierenMehrere Interfaces implementierenDefault & Static in InterfacesAbstrakte Klassen vs. InterfacesFunktionale InterfacesRückblick – ZahlungssystemÜbe selbstständig: Online-Java-Compiler