{"id":21035,"date":"2016-09-05T11:03:02","date_gmt":"2016-09-05T10:03:02","guid":{"rendered":"https:\/\/www.inovex.de\/?p=2152"},"modified":"2022-12-01T11:59:24","modified_gmt":"2022-12-01T10:59:24","slug":"das-builder-pattern-teil-1","status":"publish","type":"post","link":"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/","title":{"rendered":"Das Builder Pattern [Teil 1]"},"content":{"rendered":"<p>Vor einer Weile hatte ich die Gelegenheit festzustellen, wie hilfreich das <em>Builder Pattern<\/em> dabei ist, gleich mehrere Aspekte des Quelltextes umfangreicher (Java-) Systeme qualitativ zu verbessern. Daher m\u00f6chte ich es in einer kleinen Serie von Artikeln etwas n\u00e4her beleuchten. In diesem ersten Teil stelle ich das <em>Builder Pattern<\/em> vor und gehe auf ein paar typische Anwendungsf\u00e4lle ein. <a href=\"https:\/\/www.inovex.de\/das-builder-pattern-teil-2\/\" target=\"_blank\" rel=\"noopener\">Teil zwei<\/a> zeigt dann einige Varianten in der Umsetzung und deren Rahmenbedingungen behandeln.<!--more--><\/p>\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_79_2 counter-hierarchy ez-toc-counter ez-toc-custom ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\"><p class=\"ez-toc-title\" style=\"cursor:inherit\"><\/p>\n<\/div><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/#Grundlegende-Funktionsweise\" >Grundlegende Funktionsweise<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/#Lebenszyklus-von-Objekten\" >Lebenszyklus von Objekten<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/#Builder-vs-Factory\" >Builder vs. Factory<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/#Implementierung\" >Implementierung<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/#Telescoping-Constructor\" >Telescoping Constructor<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/#JavaBeans-und-Validierung\" >JavaBeans und Validierung<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/#Telescoping-Factory\" >Telescoping Factory<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/#Testdaten\" >Testdaten<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/#Invarianz\" >Invarianz<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/#Mehraufwand\" >Mehraufwand<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/#Weiter-gehts\" >Weiter geht&#8217;s<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-12\" href=\"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/#Join-us\" >Join us!<\/a><\/li><\/ul><\/nav><\/div>\n<h2><span class=\"ez-toc-section\" id=\"Grundlegende-Funktionsweise\"><\/span>Grundlegende Funktionsweise<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Urspr\u00fcnglich wurde das <em>Builder Pattern<\/em> von der <a href=\"https:\/\/en.wikipedia.org\/wiki\/Design_Patterns\" target=\"_blank\" rel=\"noopener\">Gang of Four<\/a> beschrieben, wobei das vollst\u00e4ndige Konzept neben dem <em>Builder<\/em> und dem von ihm erzeugten <em>Product<\/em> noch ein <em>BuilderInterface<\/em> und einen <em>Director<\/em> vorsieht, der die Erzeugung eines kompletten <em>Product<\/em> aus potentiell mehreren einzelnen Teilen zu verantworten hat. Die heute sehr stark verbreitete Form besteht in ihrer einfachen Auspr\u00e4gung h\u00e4ufig nur aus einem <em>Builder<\/em> und seinem <em>Product<\/em>.<\/p>\n<p>Grunds\u00e4tzlich ist das <em>Builder Pattern<\/em> dazu gedacht, die Erzeugung von Instanzen der Klasse <code>Product<\/code> zu unterst\u00fctzen, wenn diese eine gro\u00dfe Zahl von Attributen enth\u00e4lt. Ein <em>Builder<\/em> ist nun so etwas wie eine detailliert konfigurierbare <em>Factory<\/em>, die \u00fcber eine Reihe von Mutator-Methoden die Attributwerte f\u00fcr ein <em>Product<\/em> ansammelt um schlie\u00dflich eine Instanz mit eben diesen Werten zu erzeugen. F\u00fcr die Mutatoren hat sich die Namenskonvention <code>withField()<\/code> f\u00fcr ein Attribut <code>field<\/code> etabliert. Die Erzeugungsmethode wird meist unabh\u00e4ngig vom <em>Product<\/em> mit <code>build()<\/code> benannt und sie kann an einem <em>Builder<\/em> in der Regel beliebig oft aufgerufen werden, um eine <code>Product<\/code>-Instanz zu erzeugen, die jeweils dem aktuellen Zustand der im <em>Builder<\/em> gesammelten Attribute entspricht.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Lebenszyklus-von-Objekten\"><\/span>Lebenszyklus von Objekten<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Gerade bei reinen Datenobjekten, im Java-Kontext h\u00e4ufig als <em>Beans<\/em> bezeichnet, ist es g\u00e4ngig sie zun\u00e4chst ohne Inhalt zu erzeugen und dann <a href=\"https:\/\/en.wikipedia.org\/wiki\/JavaBeans\" target=\"_blank\" rel=\"noopener\">mit Attributwerten anzureichern<\/a>. Allerdings sind solche Objekte unmittelbar nach ihrer initialen Erzeugung im fachlichen Sinne meist inkonsistent. Erst nach dem Abschluss der Bef\u00fcllung, was ein durchaus komplexer und fehleranf\u00e4lliger Prozess sein kann, ist das Objekt <em>fertig zur Verwendung<\/em>. Diese Initialisierungsphase des <em>Products<\/em> wird nun durch eine <em>Builder<\/em>-Instanz repr\u00e4sentiert, die zu jedem Zeitpunkt f\u00fcr ihre Verwendung konsistent ist und ebenfalls immer nur vollst\u00e4ndig initialisierte und konsistente <em>Product<\/em>-Instanzen herausgibt. Und gerade komplexe Initialisierungsprozesse werden oft in mehrere Methoden aufgeteilt, welche nun mit einem g\u00fcltigen <em>Builder<\/em> aufgerufen werden, anstatt mit einem noch ung\u00fcltigen <em>Product<\/em>.<\/p>\n<p>Dar\u00fcber hinaus muss der Lebenszyklus des <em>Builders<\/em> nicht mit der Erzeugung eines <em>Product<\/em> enden, sondern er kann weitere Instanzen erzeugen, die ggf. viele der Attributwerte gemeinsam haben sollen.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Builder-vs-Factory\"><\/span>Builder vs. Factory<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Eine sch\u00f6ne Erkl\u00e4rung des Unterschiedes zwischen einem <em>Builder<\/em> und einer <em>Factory<\/em> ist ein Beispiel aus der Gastronomie. Wenn man sich in einer Trattoria die <em>Pizza des Tages<\/em> bestellt, entspricht das einem Aufruf an einer <em>Factory<\/em>. Der Aufrufer spezifiziert nicht n\u00e4her, was er haben m\u00f6chte und die Details des erzeugten <em>Product<\/em> obliegen komplett der internen Implementierung der <em>Factory<\/em>. Bestellt man aber eine <em>Pizza Vier-Jahreszeiten mit doppelt K\u00e4se, Knoblauch und Oliven anstatt der Artischocken<\/em>, dann nimmt der Aufrufer gezielt Einfluss auf die zuk\u00fcnftigen Attribute des <em>Product<\/em>, bevor dieses erzeugt wird.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Implementierung\"><\/span>Implementierung<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Es sind ein paar Randbedingungen zu erf\u00fcllen, um unerwartete Seiteneffekte zu vermeiden:<\/p>\n<ol>\n<li>Die Reihenfolge der Mutator-Aufrufe ist g\u00e4ngigerweise nicht bekannt und sollte nicht ohne Grund erzwungen werden.<\/li>\n<li>Der letzte Aufruf der jeweiligen Mutator-Methode definiert den letztendlich benutzten Wert des Attributs.<\/li>\n<li>Bei mehrmaliger Erzeugung von <em>Product<\/em>-Instanzen sollten diese von einander unabh\u00e4ngig sein.<\/li>\n<\/ol>\n<p>Es gibt aber auch einige Freiheitsgrade bei der Umsetzung eines <em>Builders<\/em>, solange er die folgenden zwei zentralen Funktionen erf\u00fcllt. Er muss in seinem inneren Zustand die Attribute f\u00fcr die Erzeugung eines <em>Product<\/em> ansammeln k\u00f6nnen und er muss <em>Product<\/em>-Instanzen erzeugen k\u00f6nnen, wenn diese Attribute valide Werte haben.<\/p>\n<p>Beispielsweise ist es sehr g\u00e4ngig \u2013 aber nicht prinzipiell notwendig \u2013 den <em>Builder<\/em> mit einem Fluent Interface auszustatten. Ob man den <em>Builder<\/em> lieber als Top-Level Klasse oder als innere Klasse des <em>Product<\/em> anlegt ist bis auf wenige F\u00e4lle nur Geschmackssache. Und ob man die Attribute des <em>Product<\/em> im <em>Builder<\/em> einzeln vorh\u00e4lt oder in einer internen <em>Product<\/em>-Instanz speichert hat wiederum verschiedene Vor- und Nachteile, die im <a href=\"https:\/\/www.inovex.de\/das-builder-pattern-teil-2\/\" target=\"_blank\" rel=\"noopener\">zweiten Teil<\/a> des Artikels diskutiert werden.<\/p>\n<p>F\u00fcr die einzelnen Funktionen gibt es verschiedene Varianten, die in bestimmten Anwendungsf\u00e4llen besonders zu empfehlen sind. Ein paar dieser F\u00e4lle m\u00f6chte ich nun kurz darstellen.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Telescoping-Constructor\"><\/span>Telescoping Constructor<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Beim Erzeugen von Datenobjekten mit vielen Attributen sind einige davon h\u00e4ufig optional. Um die verschiedenen Anwendungsgebiete dieser Objekte zu bedienen, ergibt sich als naiver Ansatz das <em>Telescoping Constructor Antipattern<\/em>, bei dem jeweils ein eigener \u00fcberladener Konstruktor mit der gerade ben\u00f6tigten Teilmenge der m\u00f6glichen Attribute angeboten wird. Abh\u00e4ngig von den Attributtypen f\u00fchrt dieses Vorgehen leicht zu gro\u00dfen Problemen bei der Auswahl des geeigneten Konstruktors und beim Lesen des Quelltextes an der Verwendungsstelle. Dies wird mit der Anzahl der (optionalen) Attribute immer gravierender.<\/p>\n<pre class=\"lang:java decode:true\" title=\"Verwirrende Verwendung \u00fcberladener Konstruktoren\">ProcessData current = new ProcessData(17L, false, false, true, null, null, \"activate\", 0, 0L, 23, items);\r\n\r\nProcessData next = new ProcessData(null, true, true, null, \"item list\", null, 14);\r\n\r\n<\/pre>\n<p>Die Meisten dieser Probleme k\u00f6nnen durch ein Konzept wie die <em>Named Parameters<\/em> behoben werden. Da so etwas aber in Java nicht direkt unterst\u00fctzt wird, bietet sich ein <em>Builder<\/em> an, wie ich schon in einem anderen <a href=\"https:\/\/www.inovex.de\/named-parameters-java-fluent-interfaces\/\" target=\"_blank\" rel=\"noopener\">Artikel<\/a> beschrieben habe. Dabei werden nur diejenigen Mutatoren verwendet, deren Attribute auch tats\u00e4chlich gesetzt werden sollen. Und diese Methoden sind aussagekr\u00e4ftig benannt.<\/p>\n<pre class=\"lang:java decode:true\" title=\"Parameter\u00fcbergabe mit benannten Mutatoren\">ProcessDataBuilder builder = new ProcessData.Builder();\r\n\r\nbuilder.withParentProcessId(17L)\r\n\r\nbuilder.withPropagateResults(true)\r\n\r\nbuilder.withStep(\"activate\")\r\n\r\nbuilder.withUserId(0L)\r\n\r\nbuilder.withOffset(23)\r\n\r\nbuilder.withItems(items)\r\n\r\nProcessData current = builder.build();\r\n\r\nbuilder = new ProcessData.Builder();\r\n\r\nbuilder.withAggregateSubResults(true)\r\n\r\nbuilder.withPropagateResults(true)\r\n\r\nbuilder.withEntityName(\"item list\")\r\n\r\nbuilder.withOffset(14)\r\n\r\nProcessData next = builder.build();\r\n\r\n<\/pre>\n<h3><span class=\"ez-toc-section\" id=\"JavaBeans-und-Validierung\"><\/span>JavaBeans und Validierung<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Das <em>JavaBeans Pattern<\/em> schreibt vor, dass Datenobjekte einen Default-Konstruktor haben und jedes Attribut \u00fcber Mutatoren und Accessoren zugegriffen werden kann. Es wird also eine leere Instanz erzeugt und diese dann mit Attributen angereichert. Das Datenobjekt existiert dabei zwischenzeitlich in einem fachlich potenziell inkonsistenten Zustand. Gerade bei der Anreicherung mit komplexen Daten kommt es oft vor, dass solche unfertigen Objekte an andere Methoden \u00fcbergeben werden, was zu Problemen f\u00fchren kann. Hier sei als Beispiel eine <code>NullPointerException<\/code> in der <code>toString()<\/code> Methode bei der Verwendung von aspektorientierten Logging-Mechanismen genannt. Es kann bei diesem Vorgehen technisch nicht forciert werden, dass eine Validierung erfolgt ist, bevor das Objekt zugreifbar und verwendbar wird.<\/p>\n<p>Ein <em>Builder<\/em> hingegen kann sehr leicht in der Erzeugermethode den aktuellen Zustand der gesammelten Attributwerte nach beliebig komplexen Vorgaben validieren und nur im Erfolgsfall eine Instanz des <em>Product<\/em> zur\u00fcckliefern. Auf diese Weise kann au\u00dferhalb des <em>Builders<\/em> zu keinem Zeitpunkt ein unvollst\u00e4ndig initialisiertes Datenobjekt existieren.<\/p>\n<pre class=\"tab-size:1 lang:java decode:true\" title=\"Validierung der Attribute vor Erzeugung des Product\">class Builder {\r\n\r\n  [...]\r\n\r\n  public Product build() throws ValidationException {\r\n\r\n    validateAttributes();\r\n\r\n    Product product = new Product();\r\n\r\n    [...]\r\n\r\n    return product;\r\n\r\n  }\r\n\r\n  private void validateAttributes() throws ValidationException { [...] }\r\n\r\n}\r\n\r\n<\/pre>\n<h3><span class=\"ez-toc-section\" id=\"Telescoping-Factory\"><\/span>Telescoping Factory<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Um das Problem zu entsch\u00e4rfen, dass unvollst\u00e4ndig initialisierte Instanzen von Datenobjekten in Umlauf kommen, wird das <em>JavaBeans Pattern<\/em> h\u00e4ufig innerhalb von (meist statischen) Factory-Methoden eingesetzt. Letztlich ist dies eine Kombination aus den vorigen beiden Pattern, da diese Factory-Methoden sich v\u00f6llig analog zu den Konstruktoren verhalten und \u2013 abgesehen von der M\u00f6glichkeit, sprechende Namen zu verwenden \u2013 dieselben Probleme bei vielen optionalen Attributen mit sich bringen. Auch hier kommt es zu einer Ansammlung von alternativen Methoden, um Instanzen zu erzeugen, denen jeweils eine wechselnde Teilmenge der Attribute \u00fcbergeben wird.<\/p>\n<p>Sowohl Problemstellung als auch L\u00f6sung ergeben sich wie beim <em>Telescoping Constructor<\/em>.<\/p>\n<p>Eine Besonderheit sind eigene Methoden f\u00fcr die Initialisierung bestimmter Teilmengen der Attribute, die dann in mehreren F\u00e4llen wiederverwendet werden k\u00f6nnen. Diesen Methoden werden dabei wiederum unfertige Instanzen \u00fcbergeben, um einen entsprechenden Teil hinzuzuf\u00fcgen. F\u00fcr solche F\u00e4lle bietet es sich an, die jeweilige <em>Builder<\/em>-Instanz an jene Methoden zu \u00fcbergeben, die dann die entsprechenden Mutatoren daran aufrufen k\u00f6nnen.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Testdaten\"><\/span>Testdaten<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Wenn ein Datenobjekt im Produktivsystem schon mit wenigen Attributen konsistent erzeugt wird und dann in den Gesch\u00e4ftsprozessen sukzessive mit weiteren Daten bef\u00fcllt wird, ist ein <em>Builder<\/em> kaum von Nutzen. Es lohnt sich aber oft, in solchen F\u00e4llen im Testcode einen <em>Builder<\/em> anzubieten, um die Unit-Tests der einzelnen Prozessphasen komfortabel mit entsprechend bef\u00fcllten Instanzen durchf\u00fchren zu k\u00f6nnen.<\/p>\n<pre class=\"lang:java decode:true\" title=\"Nachvollziebare Testdaten-Definition in Unit-Tests\">@Test\r\n\r\npublic void stepPropagatesResultToItems() {\r\n\r\nProcessData.Builder builder = new ProcessData.Builder();\r\n\r\n  builder.withParentProcessId(17L);\r\n\r\n  builder.withPropagateResults(true);\r\n\r\n  builder.withStep(\"activate\");\r\n\r\n  builder.withUserId(0L);\r\n\r\n  builder.withOffset(23);\r\n\r\n  step.process(builder.build());\r\n\r\n  verify(itemRepository).update(itemCaptor.capture());\r\n\r\n  assertItemsYieldProcessResult(itemCaptor.getValue());\r\n\r\n}\r\n\r\n<\/pre>\n<p>Wenn in mehreren Testf\u00e4llen <em>Product<\/em>-Instanzen mit gr\u00f6\u00dftenteils gleichen Daten ben\u00f6tigt werden, empfiehlt es sich, lokale Factory-Methoden anzulegen, die eine <em>Builder<\/em>-Instanz mit prototypisch vorbelegten Attributen liefern. Diese k\u00f6nnen dann noch beliebig angepasst werden, bevor das <em>Product<\/em> erzeugt wird.<\/p>\n<pre class=\"tab-size:2 lang:java decode:true\" title=\"Builder mit vordefinierten Standardwerten\">@Test\r\n\r\npublic void stepPropagatesResultToItems() {\r\n\r\n  ProcessData.Builder builder = aDefaultProcessData()\t\/\/ get default\r\n\r\n  builder.withParentProcessId(17L)\t\t\t\t\t\/\/ add attribute\r\n\r\n  builder.withOffset(23)\t\t\t\t\t\t\t\/\/ override default\r\n\r\n  step.process(builder.build());\t\t\t\t\t\/\/ create instance\r\n\r\n  verify(itemRepository).update(itemCaptor.capture());\r\n\r\n  assertItemsYieldProcessResult(itemCaptor.getValue());\r\n\r\n}\r\n\r\nprivate ProcessDataBuilder aDefaultProcessData() {\r\n\r\n  ProcessData.Builder builder = new ProcessData.Builder();\r\n\r\n  builder.withPropagateResults(true)\r\n\r\n  builder.withStep(\"activate\")\r\n\r\n  builder.withUserId(0L)\r\n\r\n  builder.withOffset(5)\r\n\r\n  builder.withItems(items);\r\n\r\n  return builder;\r\n\r\n}\r\n\r\n<\/pre>\n<p>Wird der <em>Builder<\/em> ausschlie\u00dflich im Test-Scope ben\u00f6tigt, bietet es sich an, solche Prototypen direkt dort als Methoden anzubieten und die verwendeten Attributwerte f\u00fcr die aufrufenden Tests zugreifbar zu machen. Diese k\u00f6nnen dann bei der Pr\u00fcfung der resultierenden oder kommunizierten Daten zum Vergleich herangezogen werden.<\/p>\n<p>Wenn es allerdings bereits einen <em>Builder<\/em> im Produktiv-Scope gibt und der Einsatz eines Test-spezifischen <em>Builders<\/em> dennoch n\u00fctzlich w\u00e4re, so kann \u00fcber eine Vererbungshierarchie eine teilweise Wiederverwendung erreicht werden. Hierbei ist allerdings Obacht geboten, denn die Kombination dieser Konzepte birgt einige Fallstricke. Dies habe ich in einem weiteren <a href=\"https:\/\/www.inovex.de\/das-fluent-interface-im-kontext-von-vererbung-und-polymorphie\/\" target=\"_blank\" rel=\"noopener\">Artikel<\/a> im Detail ausgef\u00fchrt.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Invarianz\"><\/span>Invarianz<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Die Invarianz von Datenobjekten, also die Unver\u00e4nderlichkeit des internen Zustands nach der Erzeugung, gewinnt dieser Tage immer mehr an Bedeutung, insbesondere da sie als L\u00f6sungsansatz f\u00fcr viele Probleme in nebenl\u00e4ufigen Systemen gilt. Diese Eigenschaft in einer Klasse technisch zu forcieren f\u00fchrt meist dazu, dass die Initialisierung umst\u00e4ndlicher und vor allem unflexibler wird. Es gibt keine Mutatoren, und Attribute k\u00f6nnen nur gemeinsam und vollst\u00e4ndig per Konstruktor \u00fcbergeben werden.<\/p>\n<p>Ein <em>Builder<\/em> kann nun eine sehr komfortable M\u00f6glichkeit anbieten, unver\u00e4nderliche Instanzen zu erzeugen, da er selbst nicht unver\u00e4nderlich ist und flexibel mit Attributwerten angereichert werden kann. Dabei kann mit der Sichtbarkeit von Konstruktoren und der <em>Builder<\/em>-Klasse auch noch beeinflusst werden, welche Komponenten \u00fcberhaupt <em>Product<\/em>-Instanzen erzeugen k\u00f6nnen. Gegebenenfalls muss der <em>Builder<\/em> daf\u00fcr als innere Klasse des <em>Product<\/em> definiert werden.<\/p>\n<pre class=\"lang:java decode:true\" title=\"Invariante Objekte mit einem Builder erzeugen\">public final class ImmutableConfig implements Config {\r\n\r\n  private final String value;\r\n\r\n  public String getValue() {\r\n\r\n    return value;\r\n\r\n  }\r\n\r\n  private ImmutableConfig(String value) {\t\/\/ only visible to internal Builder\r\n\r\n    this.value = value;\r\n\r\n  }\r\n\r\n  static Builder aConfig() {\t\t\t\/\/ only visible to same package\r\n\r\n    return new Builder();\r\n\r\n  }\r\n\r\n  static final class Builder {\t\t\t\/\/ only visible to same package\r\n\r\n    private Builder() {}\t\t\t\/\/ only visible to ImmutableConfig\r\n\r\n    private String value;\r\n\r\n    public void withValue(String value) {\r\n\r\n      this.value = value;\r\n\r\n    }\r\n\r\n    public Config build() {\r\n\r\n      return new ImmutableConfig(value);\r\n\r\n    }\r\n\r\n  }\r\n\r\n}\r\n\r\n<\/pre>\n<h2><span class=\"ez-toc-section\" id=\"Mehraufwand\"><\/span>Mehraufwand<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Das gr\u00f6\u00dfte Gegenargument f\u00fcr den Einsatz eines <em>Builders<\/em> ist der damit einhergehende Mehraufwand f\u00fcr dessen Implementierung. Letztlich muss f\u00fcr jede <em>Product<\/em>-Klasse eine weitere <em>Builder<\/em>-Klasse gepflegt werden, in der s\u00e4mtliche Attribute streng genommen dupliziert vorliegen. Es entsteht die Notwendigkeit f\u00fcr mehr stupide Flei\u00dfarbeit.<\/p>\n<p>Das ist tats\u00e4chlich nicht zu leugnen, allerdings gibt es die einfache M\u00f6glichkeit, diese stupide Flei\u00dfarbeit automatisiert erledigen zu lassen. Der \u00fcberwiegende Teil der Implementierung eines <em>Builders<\/em> h\u00e4ngt direkt von der internen Struktur des <em>Product<\/em> ab und kann sehr simpel generiert werden. Die Attribute werden dem <em>Product<\/em> entsprechend nachgebildet, die Mutatoren und sonstige Namen k\u00f6nnen hergeleitet werden und die restlichen Freiheitsgrade k\u00f6nnen durch eine der Implementierungsvarianten vorgegeben werden. Entsprechend sind f\u00fcr die g\u00e4ngigen IDEs auch einige PlugIns und Generatoren f\u00fcr <em>Builder<\/em> verf\u00fcgbar, mit denen der Mehraufwand erheblich reduziert werden kann.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Weiter-gehts\"><\/span>Weiter geht&#8217;s<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Nachdem nun die Funktionen und grundlegenden M\u00f6glichkeiten des <em>Builder Pattern<\/em> dargestellt wurden, werde ich im <a href=\"https:\/\/www.inovex.de\/das-builder-pattern-teil-2\/\" target=\"_blank\" rel=\"noopener\">n\u00e4chsten Teil<\/a> einige g\u00e4ngige Varianten f\u00fcr die Implementierung eines <em>Builders<\/em> im Detail erl\u00e4utern.<\/p>\n<p>Bis dahin k\u00f6nnte sich ein Blick auf <a href=\"https:\/\/www.inovex.de\/de\/leistungen\/\" target=\"_blank\" rel=\"noopener\">unser Dienstleistungsportfolio<\/a> lohnen. Wir freuen uns auch auf Fragen und Anregungen im Kommentarbereich unten, per Mail an <a href=\"mailto:info@inovex.de\" target=\"_blank\" rel=\"noopener\">info@inovex.de<\/a> oder telefonisch unter <a href=\"tel:+497216190210\">+49 721 619 021-0<\/a>.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Join-us\"><\/span>Join us!<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<div style=\"margin: 7px; padding: 7px; border-left: 6px solid #9CCD00;\">Wir sind au\u00dferdem immer auf der Suche nach talentierten Software-Entwickler:innen mit Schwerpunkt Java, .NET und JavaScript, die auch vor Programmiersprachen wie Clojure und Go nicht zur\u00fcckschrecken. <a title=\"Jobs bei inovex\" href=\"https:\/\/www.inovex.de\/de\/karriere\/stellenangebote\/\" target=\"_blank\" rel=\"noopener\">Unsere offenen Stellen gibt es hier<\/a>. Wir freuen uns aber immer auch \u00fcber Initiativbewerbungen!<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Vor einer Weile hatte ich die Gelegenheit festzustellen, wie hilfreich das Builder Pattern dabei ist, gleich mehrere Aspekte des Quelltextes umfangreicher (Java-) Systeme qualitativ zu verbessern. Daher m\u00f6chte ich es in einer kleinen Serie von Artikeln etwas n\u00e4her beleuchten. In diesem ersten Teil stelle ich das Builder Pattern vor und gehe auf ein paar typische [&hellip;]<\/p>\n","protected":false},"author":25,"featured_media":12718,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"ep_exclude_from_search":false,"footnotes":""},"tags":[68],"service":[425],"coauthors":[{"id":25,"display_name":"Sebastian Schmidt","user_nicename":"sschmidt"}],"class_list":["post-21035","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","tag-backend","service-backend"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Das Builder Pattern [Teil 1] - inovex GmbH<\/title>\n<meta name=\"description\" content=\"In diesem ersten Teil stelle ich das Builder Pattern vor und gehe auf ein paar typische Anwendungsf\u00e4lle ein.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Das Builder Pattern [Teil 1] - inovex GmbH\" \/>\n<meta property=\"og:description\" content=\"In diesem ersten Teil stelle ich das Builder Pattern vor und gehe auf ein paar typische Anwendungsf\u00e4lle ein.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/\" \/>\n<meta property=\"og:site_name\" content=\"inovex GmbH\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/inovexde\" \/>\n<meta property=\"article:published_time\" content=\"2016-09-05T10:03:02+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-12-01T10:59:24+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.inovex.de\/wp-content\/uploads\/2016\/08\/builder-pattern.png\" \/>\n\t<meta property=\"og:image:width\" content=\"2300\" \/>\n\t<meta property=\"og:image:height\" content=\"876\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Sebastian Schmidt\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/www.inovex.de\/wp-content\/uploads\/2016\/08\/builder-pattern-1024x390.png\" \/>\n<meta name=\"twitter:creator\" content=\"@inovexgmbh\" \/>\n<meta name=\"twitter:site\" content=\"@inovexgmbh\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Sebastian Schmidt\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"11\u00a0Minuten\" \/>\n\t<meta name=\"twitter:label3\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data3\" content=\"Sebastian Schmidt\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/\"},\"author\":{\"name\":\"Sebastian Schmidt\",\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/person\/a2ffffeaeaa18b9961297ca47e5f3799\"},\"headline\":\"Das Builder Pattern [Teil 1]\",\"datePublished\":\"2016-09-05T10:03:02+00:00\",\"dateModified\":\"2022-12-01T10:59:24+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/\"},\"wordCount\":1800,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.inovex.de\/de\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2016\/08\/builder-pattern.png\",\"keywords\":[\"Backend\"],\"articleSection\":[\"General\",\"Infrastructure\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/\",\"url\":\"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/\",\"name\":\"Das Builder Pattern [Teil 1] - inovex GmbH\",\"isPartOf\":{\"@id\":\"https:\/\/www.inovex.de\/de\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2016\/08\/builder-pattern.png\",\"datePublished\":\"2016-09-05T10:03:02+00:00\",\"dateModified\":\"2022-12-01T10:59:24+00:00\",\"description\":\"In diesem ersten Teil stelle ich das Builder Pattern vor und gehe auf ein paar typische Anwendungsf\u00e4lle ein.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/#primaryimage\",\"url\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2016\/08\/builder-pattern.png\",\"contentUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2016\/08\/builder-pattern.png\",\"width\":2300,\"height\":876,\"caption\":\"Builder-pattern erkl\u00e4rt anhand von Pizza, Artisckocken und Oliven\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.inovex.de\/de\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Das Builder Pattern [Teil 1]\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.inovex.de\/de\/#website\",\"url\":\"https:\/\/www.inovex.de\/de\/\",\"name\":\"inovex GmbH\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/www.inovex.de\/de\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.inovex.de\/de\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.inovex.de\/de\/#organization\",\"name\":\"inovex GmbH\",\"url\":\"https:\/\/www.inovex.de\/de\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png\",\"contentUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png\",\"width\":1921,\"height\":1081,\"caption\":\"inovex GmbH\"},\"image\":{\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/inovexde\",\"https:\/\/x.com\/inovexgmbh\",\"https:\/\/www.instagram.com\/inovexlife\/\",\"https:\/\/www.linkedin.com\/company\/inovex\",\"https:\/\/www.youtube.com\/channel\/UC7r66GT14hROB_RQsQBAQUQ\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/person\/a2ffffeaeaa18b9961297ca47e5f3799\",\"name\":\"Sebastian Schmidt\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/person\/image\/5f905a8b3627c2eb15cdb285c29fe6cf\",\"url\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/Avatar_3000-scaled-96x96.jpg\",\"contentUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/Avatar_3000-scaled-96x96.jpg\",\"caption\":\"Sebastian Schmidt\"},\"url\":\"https:\/\/www.inovex.de\/de\/blog\/author\/sschmidt\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Das Builder Pattern [Teil 1] - inovex GmbH","description":"In diesem ersten Teil stelle ich das Builder Pattern vor und gehe auf ein paar typische Anwendungsf\u00e4lle ein.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/","og_locale":"de_DE","og_type":"article","og_title":"Das Builder Pattern [Teil 1] - inovex GmbH","og_description":"In diesem ersten Teil stelle ich das Builder Pattern vor und gehe auf ein paar typische Anwendungsf\u00e4lle ein.","og_url":"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/","og_site_name":"inovex GmbH","article_publisher":"https:\/\/www.facebook.com\/inovexde","article_published_time":"2016-09-05T10:03:02+00:00","article_modified_time":"2022-12-01T10:59:24+00:00","og_image":[{"width":2300,"height":876,"url":"https:\/\/www.inovex.de\/wp-content\/uploads\/2016\/08\/builder-pattern.png","type":"image\/png"}],"author":"Sebastian Schmidt","twitter_card":"summary_large_image","twitter_image":"https:\/\/www.inovex.de\/wp-content\/uploads\/2016\/08\/builder-pattern-1024x390.png","twitter_creator":"@inovexgmbh","twitter_site":"@inovexgmbh","twitter_misc":{"Verfasst von":"Sebastian Schmidt","Gesch\u00e4tzte Lesezeit":"11\u00a0Minuten","Written by":"Sebastian Schmidt"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/#article","isPartOf":{"@id":"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/"},"author":{"name":"Sebastian Schmidt","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/person\/a2ffffeaeaa18b9961297ca47e5f3799"},"headline":"Das Builder Pattern [Teil 1]","datePublished":"2016-09-05T10:03:02+00:00","dateModified":"2022-12-01T10:59:24+00:00","mainEntityOfPage":{"@id":"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/"},"wordCount":1800,"commentCount":0,"publisher":{"@id":"https:\/\/www.inovex.de\/de\/#organization"},"image":{"@id":"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/#primaryimage"},"thumbnailUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2016\/08\/builder-pattern.png","keywords":["Backend"],"articleSection":["General","Infrastructure"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/","url":"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/","name":"Das Builder Pattern [Teil 1] - inovex GmbH","isPartOf":{"@id":"https:\/\/www.inovex.de\/de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/#primaryimage"},"image":{"@id":"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/#primaryimage"},"thumbnailUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2016\/08\/builder-pattern.png","datePublished":"2016-09-05T10:03:02+00:00","dateModified":"2022-12-01T10:59:24+00:00","description":"In diesem ersten Teil stelle ich das Builder Pattern vor und gehe auf ein paar typische Anwendungsf\u00e4lle ein.","breadcrumb":{"@id":"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/#primaryimage","url":"https:\/\/www.inovex.de\/wp-content\/uploads\/2016\/08\/builder-pattern.png","contentUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2016\/08\/builder-pattern.png","width":2300,"height":876,"caption":"Builder-pattern erkl\u00e4rt anhand von Pizza, Artisckocken und Oliven"},{"@type":"BreadcrumbList","@id":"https:\/\/www.inovex.de\/de\/blog\/das-builder-pattern-teil-1\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.inovex.de\/de\/"},{"@type":"ListItem","position":2,"name":"Das Builder Pattern [Teil 1]"}]},{"@type":"WebSite","@id":"https:\/\/www.inovex.de\/de\/#website","url":"https:\/\/www.inovex.de\/de\/","name":"inovex GmbH","description":"","publisher":{"@id":"https:\/\/www.inovex.de\/de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.inovex.de\/de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/www.inovex.de\/de\/#organization","name":"inovex GmbH","url":"https:\/\/www.inovex.de\/de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/","url":"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png","contentUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png","width":1921,"height":1081,"caption":"inovex GmbH"},"image":{"@id":"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/inovexde","https:\/\/x.com\/inovexgmbh","https:\/\/www.instagram.com\/inovexlife\/","https:\/\/www.linkedin.com\/company\/inovex","https:\/\/www.youtube.com\/channel\/UC7r66GT14hROB_RQsQBAQUQ"]},{"@type":"Person","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/person\/a2ffffeaeaa18b9961297ca47e5f3799","name":"Sebastian Schmidt","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/person\/image\/5f905a8b3627c2eb15cdb285c29fe6cf","url":"https:\/\/www.inovex.de\/wp-content\/uploads\/Avatar_3000-scaled-96x96.jpg","contentUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/Avatar_3000-scaled-96x96.jpg","caption":"Sebastian Schmidt"},"url":"https:\/\/www.inovex.de\/de\/blog\/author\/sschmidt\/"}]}},"_links":{"self":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts\/21035","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/users\/25"}],"replies":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/comments?post=21035"}],"version-history":[{"count":2,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts\/21035\/revisions"}],"predecessor-version":[{"id":33626,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts\/21035\/revisions\/33626"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/media\/12718"}],"wp:attachment":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/media?parent=21035"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/tags?post=21035"},{"taxonomy":"service","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/service?post=21035"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/coauthors?post=21035"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}