Entwurfsmuster (Design Patterns): Erzeugungsmuster in Java
Thema:
Autor:
E-Mail:
Web:
Thema dieses Blog-Artikels sind die Erzeugungsmuster (Creational Patterns), die als einer von drei Grundtypen innerhalb der Entwurfsmuster (Design Patterns) angesiedelt sind.
Entwurfsmuster (Design Patterns) sind in der Softwarearchitektur und -entwicklung allgemeine, wiederverwendbare und bewährte Lösungsmuster für wiederkehrende Entwurfsprobleme. Sie bilden somit eine wiederverwendbare Vorlage zur Problemlösung, welche in einem bestimmten Kontext eingesetzt werden kann. Es existieren drei unterschiedliche Grundtypen von Entwurfsmustern (Design Patterns): Erzeugungsmuster (Creational Patterns), Strukturmuster (Structural Patterns) und Verhaltensmuster (Behavioral Patterns).
Erzeugungsmuster werden für die Objekterzeugung verwendet und entkoppeln die Objektkonstruktion von der Objektrepräsentation.
Beispiele für Erzeugungsmuster sind: Abstrakte Fabrik, Fabrikmethode, Erbauer, Prototyp und Singleton.
Nachfolgend wird für zwei Erzeugungsmuster (Abstrakte Fabrik und Erbauer) jeweils ein entsprechendes UML Diagramm dargestellt und erläutert sowie eine beispielhafte Implementierung aufgezeigt. Die Implementierung erfolgt in der objektorientierten Programmiersprache Java.
Abstrakte Fabrik:
Das Entwurfsmuster „Abstrakte Fabrik“ (abstract factory pattern) definiert eine Schnittstelle zur Erzeugung einer Familie von Objekten, wobei die konkreten Klassen der zu instanziierenden Objekte nicht näher festgelegt werden.
Es wird eingesetzt, 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
- wenn in einer Klassenbibliothek die Schnittstellen von Produkten ohne deren Implementierung bereitgestellt werden sollen.
Das UML Diagramm für das Entwurfsmuster „Abstrakte Fabrik“ stellt sich wie folgt dar:
UML Diagramm für das Entwurfsmuster "Abstrakte Fabrik"
Die Akteure des Entwurfsmusters „Abstrakte Fabrik“ sind wie folgt:
AbstractFactory (AbstrakteFabrik):
Definiert eine Schnittstelle zur Erzeugung abstrakter Produkte einer Produktfamilie.
ConcreteFactory (KonkreteFabrik):
Erzeugt konkrete Produkte einer Produktfamilie durch Implementierung der Schnittstelle.
AbstractProduct (AbstraktesProdukt):
Definiert eine Schnittstelle für eine Produktart.
ConcreteProduct (KonkretesProdukt):
Definiert ein konkretes Produkt einer Produktart durch Implementierung der Schnittstelle, wird durch die korrespondierende konkrete Fabrik erzeugt.
Client (Klient):
Verwendet die Schnittstellen der abstrakten Fabrik und der abstrakten Produkte.
Eine beispielhafte Java-Implementierung für das Entwurfsmuster „Abstrakte Fabrik“ sieht wie folgt aus:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
/* * Design Pattern: Abstract Factory Pattern (Abstrakte Fabrik) * Modified code example based on the english wikipedia article: Abstract factory pattern * URL: https://en.wikipedia.org/wiki/Abstract_factory_pattern * * Company: HyperCube IT Solutions * Author: Christian Paulus * Email: c.paulus@hypercube.biz * Web: www.hypercube.biz */ package design_patterns.creational_patterns; /* Client (Klient) */ class AbstractFactoryPatternClient { public static void main(String args[]) { System.out.println("== Abstract Factory Pattern Application =="); System.out.println(); // usage of ConcreteFactory1 System.out.println("ConcreteFactory1 (WindowsGUIFactory):"); GUIFactory guiFactoryWindows = new WindowsGUIFactory(); TextField textFieldWindows = guiFactoryWindows.createTextField(); // <<create>> product A1 textFieldWindows.drawTextField(); Button buttonWindows = guiFactoryWindows.createButton(); // <<create>> product B1 buttonWindows.drawButton(); System.out.println(); // usage of ConcreteFactory2 System.out.println("ConcreteFactory2 (LinuxGUIFactory):"); GUIFactory guiFactoryLinux = new LinuxGUIFactory(); TextField textFieldLinux = guiFactoryLinux.createTextField(); // <<create>> product A2 textFieldLinux.drawTextField(); Button buttonLinux = guiFactoryLinux.createButton(); // <<create>> product B2 buttonLinux.drawButton(); } } /* AbstractFactory (AbstrakteFabrik) */ interface GUIFactory { public TextField createTextField(); // create product A public Button createButton(); // create product B } /* ConcreteFactory1 (KonkreteFabrik1) */ class WindowsGUIFactory implements GUIFactory { // <<create>> product A public TextField createTextField() { /* Implementation */ // ... System.out.println("WindowsGUIFactory:createTextField"); return new WindowsTextField(); } // <<create>> product B public Button createButton() { /* Implementation */ // ... System.out.println("WindowsGUIFactory:createButton"); return new WindowsButton(); } } /* ConcreteFactory2 (KonkreteFabrik2) */ class LinuxGUIFactory implements GUIFactory { // <<create>> product A public TextField createTextField() { /* Implementation */ // ... System.out.println("LinuxGUIFactory:createTextField"); return new LinuxTextField(); } // <<create>> product B public Button createButton() { /* Implementation */ // ... System.out.println("LinuxGUIFactory:createButton"); return new LinuxButton(); } } /* AbstractProductA (AbstraktesProduktA) */ interface TextField { public void drawTextField(); // ... } /* ConcreteProductA1 (KonkretesProduktA1) */ class WindowsTextField implements TextField { public void drawTextField() { /* Implementation */ // ... System.out.println("WindowsTextField:drawTextField"); } // ... } /* ConcreteProductA2 (KonkretesProduktA2) */ class LinuxTextField implements TextField { public void drawTextField() { /* Implementation */ // ... System.out.println("LinuxTextField:drawTextField"); } // ... } /* AbstractProductB (AbstraktesProduktB) */ interface Button { public void drawButton(); // ... } /* ConcreteProductB1 (KonkretesProduktB1) */ class WindowsButton implements Button { public void drawButton() { /* Implementation */ // ... System.out.println("WindowsButton:drawButton"); } // ... } /* ConcreteProductB2 (KonkretesProduktB2) */ class LinuxButton implements Button { public void drawButton() { /* Implementation */ // ... System.out.println("LinuxButton:drawButton"); } // ... } |
Für die Übersichtlichkeit dieses Beispiels wurden alle Java-Klassen in einer Java-Datei aufgeführt, anstatt wie üblich jede Java-Klasse in einer eigenen Java-Datei aufzuführen.
Die Ausführung der Java-Datei AbstractFactoryPattern.java in der Eclipse IDE liefert das folgende Ergebnis:
Ausführung von "AbstractFactoryPattern.java" in Eclipse
Erbauer
Das Entwurfsmuster „Erbauer“ (builder pattern) trennt die Konstruktion komplexer Objekte von deren Repräsentationen, wodurch dieselben Konstruktionsprozesse wiederverwendet werden können.
Es wird eingesetzt, wenn
- zu einem komplexen Objekt unterschiedliche Repräsentationen existieren sollen,
- die Konstruktion eines komplexen Objekts unabhängig von der Erzeugung der Bestandteile sein soll oder
- der Konstruktionsablauf einen internen Zustand erfordert, der vor einem Klienten verborgen werden soll.
Das UML Diagramm für das Entwurfsmuster „Erbauer“ stellt sich wie folgt dar:
UML Diagramm für das Entwurfsmuster "Erbauer"
Die Akteure des Entwurfsmusters „Erbauer“ sind wie folgt:
Director (Direktor):
Konstruiert ein komplexes Objekt unter Verwendung der Schnittstelle des Erbauers.
Arbeitet eng mit dem Erbauer zusammen: Er weiß, welche Baureihenfolge der Erbauer verträgt oder benötigt.
Entkoppelt den Konstruktionsablauf vom Klienten.
Builder (Erbauer):
Spezifiziert eine abstrakte Schnittstelle zur Erzeugung der Teile eines komplexen Objektes.
ConcreteBuilder (KonkreterErbauer):
Erzeugt die Teile des komplexen Objekts durch Implementierung der Schnittstelle.
Definiert und verwaltet die von ihm erzeugte Repräsentation des Produkts.
Product (Produkt):
Das Produkt repräsentiert das zu konstruierende komplexe Objekt.
Client (Klient):
Verwendet den Direktor und konkrete Erbauer zur Konstruktion komplexer Objekte (Produkte).
Eine beispielhafte Java-Implementierung für das Entwurfsmuster „Erbauer“ sieht wie folgt aus:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
/* * Design Pattern: Builder Pattern (Erbauer) * Modified code example based on the english wikipedia article: Builder pattern * URL: https://en.wikipedia.org/wiki/Builder_pattern * * Company: HyperCube IT Solutions * Author: Christian Paulus * Email: c.paulus@hypercube.biz * Web: www.hypercube.biz */ package design_patterns.creational_patterns; /* Client (Klient) */ class BuilderPatternClient { public static void main(String args[]) { System.out.println("== Builder Pattern Application =="); System.out.println(); // create concrete builder LotusBuilder lotusBuilder = new LotusBuilder(); // create director CarBuildDirector carBuildDirector = new CarBuildDirector(lotusBuilder); carBuildDirector.constructCar(); // construct() // get result of 'ConcreteBuilder' System.out.println("'getResult()' of 'ConcreteBuilder':"); Car myLotus = lotusBuilder.getCar(); // getResult(): Product myLotus.drive(); } } /* Builder (Erbauer) */ interface CarBuilder { public void buildChassis(); // buildPartA() public void buildBody(); // buildPartB() public void buildEngine(); // buildPartC() } /* ConcreteBuilder (KonkreterErbauer) */ class LotusBuilder implements CarBuilder { protected Car car = null; public LotusBuilder() { car = new Car(); // <<create>> product } public void buildChassis() { // buildPartA() car.setChassis("Lotus Esprit GT3: CHASSIS"); } public void buildBody() { // buildPartB() car.setBody("Lotus Esprit GT3: BODY"); car.setColor("dark blue"); } public void buildEngine() { // buildPartC() car.setEngine("Lotus Esprit GT3: ENGINE"); } public Car getCar() { // getResult(): Product return car; } } /* Director (Direktor) */ class CarBuildDirector { private CarBuilder carBuilder = null; // builder: Builder public CarBuildDirector(CarBuilder carBuilder) { this.carBuilder = carBuilder; } public void constructCar() { // construct() carBuilder.buildChassis(); carBuilder.buildBody(); carBuilder.buildEngine(); } } /* Product (Produkt) */ class Car { private String chassis; private String body; private String engine; private String color = "black"; public String getChassis() { return chassis; } public void setChassis(String chassis) { this.chassis = chassis; } public String getBody() { return body; } public void setBody(String body) { this.body = body; } public String getEngine() { return engine; } public void setEngine(String engine) { this.engine = engine; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } public void drive() { System.out.println("You drive your car ..."); } } |
Für die Übersichtlichkeit dieses Beispiels wurden alle Java-Klassen in einer Java-Datei aufgeführt, anstatt wie üblich jede Java-Klasse in einer eigenen Java-Datei aufzuführen.
Die Ausführung der Java-Datei BuilderPattern.java in der Eclipse IDE liefert das folgende Ergebnis:
Ausführung von "BuilderPattern.java" in Eclipse
Quellenangaben:
- Gamma, Erich et al. – Design Patterns: Elements of Reusable Object-Oriented Software; Addison-Wesley, 2009
- Gamma, Erich et al. – Entwurfsmuster: Elemente wiederverwendbarer objektorientierter Software; Addison-Wesley, 2011
- Gamma, Erich et al. – Design Patterns: Entwurfsmuster als Elemente wiederverwendbarer objektorientierter Software; mitp, 2015
- Wikipedia – Abstract factory pattern: https://en.wikipedia.org/wiki/Abstract_factory_pattern
- Wikipedia – Abstrake Fabrik: https://de.wikipedia.org/wiki/Abstrakte_Fabrik
- Wikipedia – Builder pattern: https://en.wikipedia.org/wiki/Builder_pattern
- Wikipedia – Erbauer (Entwurfsmuster): https://de.wikipedia.org/wiki/Erbauer_(Entwurfsmuster)