Factory Method Pattern Bedeutung: Das Muster ist eines der sogenannten GoF-Entwurfsmuster (Gang offour). Es bezeichnet ein Muster, bei dem die Schnittstelle zur Erstellung eines Objektes eine (abstrakte) Methode einer Oberklasse ist. Die konkrete Implementierung der Erzeugung neuer Objekte findet jedoch nicht in der Oberklasse statt, sondern in von ihr abgeleiteten Unterklassen, die die besagte abstrakte Methode implementieren. Das Muster beschreibt somit die Erzeugung von Produktobjekten, deren konkreter Typ von Unterklassen einer Erzeugerklasse bestimmt wird und der ein Untertypeiner abstrakten Produktklasse ist. Es wird manchmal auch als virtueller Konstruktor(virtual constructor) bezeichnet.
Beispiel class Complex { public static Complex fromcartesian(double real, double imaginary){ return new Complex(real, imaginary); public static Complex frompolar(double modulus, double angle){ return new Complex(modulus * cos(angle), modulus * sin(angle)); private Complex(double a, double b){ //... Complex c = Complex.fromPolar(1, pi);
Factory Method Pattern (UML-Diagramm)
Verwendung: Die Fabrikmethode (in der GoF-Bedeutung) findet Anwendung, wenn eine Klasse die von ihr zu erzeugenden Objekte nicht kennen kann bzw. soll, oder wenn Unterklassen bestimmen sollen, welche Objekte erzeugt werden. Typische Anwendungsfälle sind Frameworks und Klassenbibliotheken. Akteure: Das Produktist der Basistyp(abstracteKlasse oder Schnittstelle) für das zu erzeugende Produkt. Der Erzeugerdeklariert die Fabrikmethode, um ein solches Produkt zu erzeugen und kann eine Default- Implementierung beinhalten. KonkretesProduktimplementiert die Produkt-Schnittstelle. (Es ist also ein konkreter Subtyp von Produkt). KonkreterErzeugerüberschreibt die Fabrikmethode, um die ihm entsprechenden konkreten Produkte zu erzeugen (z. B. indem er den Konstruktor einer konkreten Produkt- Klasse aufruft).
Vorteile: Fabrikmethoden entkoppeln ihre Aufrufer (Clients) von Implementierungen konkreter Produkt-Klassen. Das ist insbesondere wertvoll, wenn Frameworks sich während der Lebenszeit einer Applikation weiterentwickeln -so können zu einem späteren Zeitpunkt Instanzen anderer Klassen erzeugt werden, ohne dass sich die Applikation ändern muss. Viele objektorientierte Programmiersprachen schreiben den Namen des Konstruktorsvor. Demgegenüber kann eine Fabrikmethode einen aussagekräftigeren Namen haben und es kann mehrere Fabrikmethoden unterschiedlichen Namens und unterschiedlicher Semantik geben. Beispielsweise könnte eine Methode Color.createFromRGB()ein Farbobjekt aus RGB-Werten erzeugen, eine Methode Color.createFromHSV() ein Farbobjekt aus HSV-Werten.
Pizzeria-Kette
Schlechte Lösung String ort, typ;... if (ort.equals("berlin")) { if (typ.equals("salami")) { pizza = new BerlinerSalamiPizza(); else if (typ.equals("vegetarisch")) { pizza = new BerlinerVegetarischePizza(); else if (typ.equals("krabben")) { pizza = new BerlinerKrabbenPizza(); else if (typ.equals("thunfisch")) { pizza = new BerlinerThunfischPizza(); else if (ort.equals("münchen")) { if (typ.equals("salami")) { pizza = new MuenchenerSalamiPizza(); else if (typ.equals("vegetarisch")) { pizza = new MuenchenerVegetarischePizza(); else if (typ.equals("krabben")) { pizza = new MuenchenerKrabbenPizza(); else if (typ.equals("thunfisch")) { pizza = new MuenchenerThunfischPizza(); else { System.out.println("Fehler: Ungültiger Pizzatyp"); pizza = null;
Der Code auf der letzten Folie verletzt das Offen/Geschlossen-Prinzip: Klassen sollten offen für Erweiterungen, aber geschlossen für Veränderungensein! if (pizza!= null) { pizza.vorbereiten(); pizza.backen(); pizza.schneiden(); pizza.verpacken(); Nebenstehender Code ändert sich nicht...
Factory-Method Pattern
Bessere Lösung: Pizzeria pizzeria = new BerlinPizzeria(); Pizza pizza = pizzeria.erstellepizza("salami"); Hierbei sind Pizza und Pizzeria beides Interfaces oder abstrakte Klassen! abstract Pizza erstellepizza(string typ); ist die Factory-Methode. Die Erstellung der Produkte (Pizzas) wird gegenüber dem Client abgekapselt, so dass dieser gar nicht genau wissen muss, welche konkrete Art von Produkt tatsächlich erstellt werden.
Abstrakte Erzeugerklasse Pizzeria mit der abstrakten Fabrik- Methode public abstract class Pizzeria { // Fabrik-Methode protected abstract Pizza erstellepizza(string typ); public Pizza bestellepizza(string typ){ Pizza pizza = erstellepizza(typ); System.out.println("--- Mache nun eine " + pizza.getname() + " ---"); pizza.vorbereiten(); pizza.backen(); pizza.schneiden(); pizza.verpacken(); return pizza;
Zweck: Das Factory-Method-Muster definiert eine Klassenschnittstelle mit Operationen zum Erzeugen eines Objekts, aber lässt Unterklassen entscheiden, von welcher Klasse das zu erzeugende Objekt ist. Fabrikmethoden ermöglichen es einer Klasse, die Erzeugung von Objekten an konkrete Unterklassen zu delegieren. Anwendbarkeit: Verwenden Sie das Factory-Method-Muster, wenn Eine Klasse die Klassen von Objekten, die sie erzeugen muss, nicht im Voraus kennen kann. Eine Klasse möchte, dass ihre Unterklassen die von ihr zu erzeugenden Objekte festlegen.
Parallele Klassenhierarchien
Abstract Factory Pattern Definition: Das Abstract-Factory-Muster bietet eine Schnittstelle zum Erzeugen von Familien verwandter oder zusammenhängender Objekte, ohne ihre konkreten Klassen anzugeben. Verwendung: Die Abstrakte Fabrik findet Anwendung, wenn ein System unabhängig von der Art der Erzeugung seiner Produkte arbeiten soll, ein System mit einer oder mehreren Produktfamilien konfiguriert werden soll, eine Gruppe von Produkten erzeugt und gemeinsam genutzt werden soll oder Eine typische Anwendung ist die Erstellung einer grafischen Benutzeroberfläche mit unterschiedlichen Designs.
Abstract Factory-Pattern
Akteure : AbstrakteFabrikdefiniert eine Schnittstelle zur Erzeugung abstrakter Produkte einer Produktfamilie. KonkreteFabrikerzeugt konkrete Produkte einer Produktfamilie durch Implementierung der Schnittstelle. AbstraktesProduktdefiniert eine Schnittstelle für eine Produktart. KonkretesProduktdefiniert ein konkretes Produkt einer Produktart durch Implementierung der Schnittstelle, wird durch die korrespondierende konkrete Fabrik erzeugt. Klientverwendet die Schnittstellen der abstrakten Fabrik und der abstrakten Produkte. Vorteile : Konkrete Klassen werden isoliert. Der Austausch und das Hinzufügen von Produktfamilien ist auf einfache Art und Weise möglich.
Beispiel Pizzeria
public interface PizzaZutatenFabrik { public Teig erstelleteig(); public Sosse erstellesoße(); public Kaese erstellekäse(); public Salami erstellesalami(); public Gemuese[] erstellegemüse(); public Thunfisch erstellethunfisch(); public Krabben erstellekrabben(); Abstrakte Fabrik public class BerlinerPizzaZutatenFabrik implements PizzaZutatenFabrik { public Teig erstelleteig() { return new TeigMitDuennerKruste(); Konktete Fabrik public Sosse erstellesoße() { return new MarinaraSosse(); public Kaese erstellekäse() { return new Parmesan();...
... public Salami erstellesalami() { return new SpanischeSalami(); public Gemuese[] erstellegemüse() { Gemuese gemüse[] = { new Knoblauch(), new Zwiebeln(), new Pilze(), new Paprika() ; return gemüse; public Thunfisch erstellethunfisch() { return new ThunfischStuecke(); public Krabben erstellekrabben() { return new FrischeKrabben();
public interface Salami { public String tostring(); Abstraktes Produkt A public class ItalienischeSalami implements Salami { public String tostring() { return "Italienische Salami"; Produkt A1 public class SpanischeSalami implements Salami { public String tostring() { return "Scharfe spanische Salami"; Produkt A2
Quellen: Entwurfsmuster von Kopf bis Fuß Freeman, Eric & Freeman, Elisabeth O Reilly Entwurfsmuster Gamma, Eric et al. Addison-Wesley Design Patterns in Java Metsker, Steven J. Addison-Wesley