Builder (design sample)
The builder (English builder ) is a design pattern in the field of software development . It belongs to the category of the generation pattern (English creational patterns ) and the construction separates complex objects of their representations, whereby the same design processes can be reused. The pattern is one of the so-called GoF patterns ( Gang of Four , see Gang of Four ).
use
The use of the builder design pattern is advisable if
- different representations should exist for a complex object,
- the construction of a complex object should be independent of the creation of the components or
- the construction process requires an internal state that should be hidden from a client.
Typical applications are e.g. B. Application programs for conversion .
actors
One can distinguish between four actors: Direktor
, Erbauer
, KonkreterErbauer
and Produkt
. The builder specifies an abstract interface for creating the parts of a complex object. The concrete builder creates the parts of the complex object by implementing the interface. He also defines and manages the representation of the product he creates. It also offers an interface for reading out the product.
The director constructs a complex object using the builder's interface. The director works closely with the builder : he knows which construction sequence the builder can handle or need. The director thus decouples the construction process from the client . The product represents the complex object to be constructed.
advantages
The implementations of the construction and the representations are isolated. The builders hide their internal representation from the director. New representations can easily be inserted through new concrete builder classes. The construction process is controlled in a dedicated place (in the director); Later changes - for example a multi-phase construction process instead of a single-phase construction - can be implemented without changing the client.
disadvantage
There is a close link between the product, the specific builder and the classes involved in the construction process.
variant
You can also let the product itself implement the builder interface. This saves u. U. some classes. The created product “drags” the builder interface with it all its life, so that product parts can later be added from the outside.
Use in analysis
This pattern is rarely used in software analysis because of the difficult metaphor.
The variant in which an object itself provides procedures for adding additional parts is advantageous in pipeline-like business processes. The business process as director instructs the document as builder to create new parts and hook them into itself. For example, a file management system can attach notes to a file run in individual steps.
example
Stock exchange software records stock prices in a text file in the following format: For each stock corporation, the security identification number, name of the stock corporation, price and the number of items traded are saved in one line, separated by spaces:
515100 BASF 36,84 2850400 803200 Commerzbank 6,71 17231300 ...
Now this format is to be converted into a format such as CSV or XML . If the semicolon is used as a separator in CSV format, the above file should be converted into the following, for example:
515100;BASF;36,84;2850400 803200;Commerzbank;6,71;17231300
In XML format, however, the result of the conversion could look like this:
<Aktienkurse> <Aktie> <WKN>515100</WKN> <Name>BASF</Name> <Kurs>36,84</Kurs> <Stueckzahl>2850400</Stueckzahl> </Aktie> <Aktie> <WKN>803200</WKN> <Name>Commerzbank</Name> <Kurs>6,71</Kurs> <Stueckzahl>17231300</Stueckzahl> </Aktie> </Aktienkurse>
The following C ++ program shows the use of the builder pattern in an application for data format conversion, which can easily be expanded to include additional output formats. The director (class KursdatenUmwandler
) knows how to read and parse data in legacy format. He knows a builder who can translate parsed parts into his respective format. All concrete builders are concrete subclasses of the abstract class KursdatenBauer
. For example, the class translates XMLKursdatenBauer
parsed lines into an XML format.
The client can inform the director of the specific builder at runtime. So the output format can be changed at runtime.
To support a new output format, the class only needs to be KursdatenBauer
implemented accordingly by a specific subclass, e.g. B. by LaTeXKursdatenBauer
.
The following is important with this pattern: It is not only the individual parts that are produced that have complexity (this is taken care of by the specific producers), but also the whole to be produced is a complex object, which the director takes care of producing. The director is therefore the “specialist” for the creation of the product. He alone knows the necessary individual steps. In the example, he alone knows how to parse the old format and how to assemble the new format from it.
#include <iostream>
#include <memory>
#include <string>
using std::cin;
using std::cout;
using std::endl;
using std::shared_ptr;
using std::string;
// Abstrakter Erbauer:
class KursdatenBauer {
public:
virtual void KursdatenSchreiben(const string &wkn, const string &name,
const string &kurs,
const string &stueckzahl) = 0;
virtual void SchreibenInitialisieren() {}
virtual void SchreibenBeenden() {}
};
// Konkreter Erbauer für CSV-Dateien:
class CSVKursdatenBauer : public KursdatenBauer {
DatenRepraesentation &repr_;
public:
CSVKursdatenBauer(DatenRepraesentation &arepr) : repr_(arepr) {}
// Hier entsteht das Produkt, der Einfachheit halber auf die
// Standardausgabe geschrieben. (Es könnte auch in einen Stream
// geschrieben werden, der im Konstruktor übergeben wird.)
virtual void KursdatenSchreiben(const string &wkn, const string &name,
const string &kurs,
const string &stueckzahl) {
repr_.anhaengen(wkn)
.anhaengen(";")
.anhaengen(name)
.anhaengen(";")
.anhaengen(kurs)
.anhaengen(";")
.anhaengen(stueckzahl);
}
virtual void SchreibenInitialisieren() { repr_.loeschen(); }
};
// konkreter Erbauer für XML-Dateien:
class XMLKursdatenBauer : public KursdatenBauer {
DatenRepraesentation &repr_;
public:
XMLKursdatenBauer(DatenRepraesentation &arepr) : repr_(arepr) {}
virtual void KursdatenSchreiben(const string &wkn, const string &name,
const string &kurs,
const string &stueckzahl) {
repr_.anhaengen("\t<Aktie>").anhaengen("\n");
repr_.anhaengen("\t\t<WKN>").anhaengen(wkn).anhaengen("</WKN>\n");
repr_.anhaengen("\t\t<Name>").anhaengen(name).anhaengen("</Name>\n");
repr_.anhaengen("\t\t<Kurs>").anhaengen(kurs).anhaengen("</Kurs>\n");
repr_.anhaengen("\t\t<Stueckzahl>").anhaengen(stueckzahl).anhaengen("</Stueckzahl>\n");
repr_.anhaengen("\t</Aktie>").anhaengen("\n");
}
virtual void SchreibenInitialisieren() {
repr_.loeschen();
repr_.anhaengen("<Aktienkurse>").anhaengen("\n");
}
virtual void SchreibenBeenden() {
repr_.anhaengen("</Aktienkurse>").anhaengen("\n");
}
};
// Produkt
class DatenRepraesentation {
string text;
public:
DatenRepraesentation &anhaengen(const string &teil) {
text += teil;
return (*this);
}
void ausgeben() {
cout << text << endl;
}
void loeschen() {
text.clear();
}
};
// Direktor:
class KursdatenUmwandler {
shared_ptr<KursdatenBauer> _kursdatenBauer;
public:
void KursdatenBauerSetzen(shared_ptr<KursdatenBauer> kb) {
_kursdatenBauer = kb;
}
void KursdatenParsenUndSchreiben() {
_kursdatenBauer->SchreibenInitialisieren();
// Zeile für Zeile von STDIN lesen und in geeignete Teile zerlegen
while (!cin.eof()) {
string wkn, name, kurs, stueckzahl;
// lesen:
cin >> wkn >> name >> kurs >> stueckzahl;
if (wkn.empty()) {
break;
}
// schreiben:
_kursdatenBauer->KursdatenSchreiben(wkn, name, kurs, stueckzahl);
}
_kursdatenBauer->SchreibenBeenden();
}
};
// Klient:
int main() {
DatenRepraesentation repraesentation;
shared_ptr<KursdatenBauer> csvKursdatenBauer(new CSVKursdatenBauer(repraesentation));
shared_ptr<KursdatenBauer> xmlKursdatenBauer(new XMLKursdatenBauer(repraesentation));
KursdatenUmwandler kursdatenUmwandler;
kursdatenUmwandler.KursdatenBauerSetzen(xmlKursdatenBauer);
// oder
// kursdatenUmwandler.KursdatenBauerSetzen(csvKursdatenBauer);
kursdatenUmwandler.KursdatenParsenUndSchreiben();
// Aktion mit dem Produkt ausführen
repraesentation.ausgeben();
}
Related design patterns
The abstract factory is similar to the builder because it can also create complex objects. The focus here is not on the structure, but on the abstraction from the specific type of the objects created. The builder often creates a compound word (design pattern) . In the case of conversion applications, the director - or even the builder - is often a visitor or possibly an interpreter (design sample) of the structure to be converted.
Web links
Individual evidence
- ↑ Erich Gamma , Richard Helm , Ralph Johnson , John Vlissides : Design pattern . 5th edition. Addison-Wesley, 1996, ISBN 3-8273-1862-9 , pp. 119 .
- ^ Karl Eilebrecht, Gernot Starke: Patterns compact. Design patterns for effective software development . 3. Edition. Spektrum Akademischer Verlag, 2010, ISBN 978-3-8274-2525-6 , pp. 29 , doi : 10.1007 / 978-3-8274-2526-3 .