Schauen wir uns die Optionen an, in denen wir den Validierungscode platzieren können:
- Innerhalb der Setter in Builder.
- Innerhalb der
build()
Methode.
- Innerhalb der erstellten Entität: Sie wird in der
build()
Methode aufgerufen , wenn die Entität erstellt wird.
Option 1 ermöglicht es uns, Probleme früher zu erkennen, aber es kann komplizierte Fälle geben, in denen wir Eingaben nur mit dem vollständigen Kontext validieren können, wodurch zumindest ein Teil der Validierung in der build()
Methode durchgeführt wird. Daher führt die Auswahl von Option 1 zu inkonsistentem Code, wobei ein Teil der Validierung an einer Stelle und ein anderer Teil an einer anderen Stelle ausgeführt wird.
Option 2 ist nicht wesentlich schlechter als Option 1, da die Setter in Builder normalerweise direkt vor den build()
Interfaces aufgerufen werden , insbesondere bei fließenden Interfaces. Somit ist es in den meisten Fällen immer noch möglich, ein Problem früh genug zu erkennen. Wenn der Builder jedoch nicht die einzige Möglichkeit ist, ein Objekt zu erstellen, wird der Validierungscode dupliziert, da Sie ihn überall dort benötigen, wo Sie ein Objekt erstellen. Die logischste Lösung besteht in diesem Fall darin, die Validierung so nah wie möglich am erstellten Objekt, dh innerhalb des Objekts, zu platzieren. Und das ist die Option 3 .
Unter SOLID-Gesichtspunkten verstößt das Versetzen der Validierung in Builder auch gegen SRP: Die Builder-Klasse ist bereits dafür verantwortlich, die Daten zu aggregieren, um ein Objekt zu erstellen. Bei der Validierung werden Verträge für den eigenen internen Status erstellt. Es ist eine neue Verantwortung, den Status eines anderen Objekts zu überprüfen.
Aus meiner Sicht ist es daher nicht nur besser, aus Designsicht spät zu scheitern, sondern auch besser, innerhalb der konstruierten Entität zu scheitern, als im Builder selbst.
UPD: Dieser Kommentar erinnerte mich an eine weitere Möglichkeit, wenn die Validierung im Builder (Option 1 oder 2) sinnvoll ist. Es ist sinnvoll, wenn der Builder eigene Verträge für die von ihm erstellten Objekte hat. Angenommen, wir haben einen Builder, der eine Zeichenfolge mit einem bestimmten Inhalt erstellt, z. B. eine Liste von Nummernbereichen 1-2,3-4,5-6
. Dieser Builder hat möglicherweise eine Methode wie addRange(int min, int max)
. Die resultierende Zeichenfolge weiß nichts über diese Zahlen und sollte es auch nicht wissen müssen. Der Builder selbst definiert das Format der Zeichenfolge und die Einschränkungen für die Zahlen. Daher muss die Methode addRange(int,int)
die eingegebenen Zahlen validieren und eine Ausnahme auslösen, wenn max kleiner als min ist.
Die allgemeine Regel ist jedoch, nur die vom Bauherrn selbst definierten Verträge zu validieren.