Angenommen, Sie haben eine Komponente mit sehr vielen Optionen, um ihr Verhalten zu ändern. Denken Sie an eine Tabelle von Daten mit etwas Sortieren, Filtern, Paging, usw. Die Optionen könnten dann isFilterable
, isSortable
, defaultSortingKey
usw. sein. Natürlich wird es ein Parameter-Objekt geben Um all diese einzukapseln, nennen wir es TableConfiguration
. Natürlich wollen wir keinen riesigen Konstruktor oder eine Menge teleskopischer Konstruktoren haben, daher verwenden wir einen Builder , TableConfigurationBuilder
. Die Beispielverwendung könnte sein:
So weit, so gut, eine Tonne von SO-Fragen beschäftigt sich schon damit.
Es gibt jetzt eine Tonne Tables
und jeder von ihnen verwendet seine eigene TableConfiguration
. Es wird jedoch nicht der gesamte "Konfigurationsraum" einheitlich verwendet: Sagen wir, die meisten Tabellen sind filterbar, und die meisten davon sind paginiert. Nehmen wir an, es gibt nur 20 verschiedene Kombinationen von Konfigurationsoptionen, die sinnvoll sind und tatsächlich verwendet werden. Nach dem DRY-Prinzip leben diese 20 Kombinationen in Methoden wie diesen:
Wie man diese 20 Methoden verwaltet, so dass Entwickler, die neue Tabellen hinzufügen, die gewünschte Kombination leicht finden oder eine neue hinzufügen können, falls sie noch nicht existiert?
Alles oben genannte benutze ich bereits, und es funktioniert einigermaßen gut, wenn ich eine existierende Tabelle zum kopieren-einfügen habe ("es ist genau wie Kunden"). Aber jedes Mal, wenn etwas Außergewöhnliches erforderlich ist, ist es schwer herauszufinden:
Ich habe versucht, den Methoden einige sehr aussagekräftige Namen zu geben, um auszudrücken, welche Konfigurationsoptionen im Inneren erstellt werden, aber sie skaliert nicht wirklich gut ...
Als ich über die großen Antworten nachdachte, fiel mir noch eine Sache ein: Bonuspunkte für die typsichere Gruppierung von Tabellen mit gleicher Konfiguration. Mit anderen Worten, beim Betrachten einer Tabelle sollte es möglich sein, alle ihre "Zwillinge" durch etwas wie gehe zur Definition und finde alle Referenzen zu finden.
Ich denke, wenn Sie das Builder-Muster bereits verwenden, dann wäre es am besten, sich an das Builder-Muster zu halten. Es gibt keine Vorteile darin, Methoden oder eine Enumeration zu haben, um build das am häufigsten verwendete TableConfiguration
zu erstellen.
Sie haben jedoch einen gültigen Punkt in Bezug auf DRY. Warum setzen Sie die meisten gängigen Flags für fast jeden Builder an vielen verschiedenen Orten?
Sie müssten also die Einstellung der gebräuchlichsten Flags kapseln (um sich nicht zu wiederholen) und trotzdem zusätzliche Flags über diese gemeinsame Basis setzen. Außerdem müssen Sie auch spezielle Fälle unterstützen. In Ihrem Beispiel erwähnen Sie, dass die meisten Tabellen filterbar und paginiert sind.
Während das Builder-Muster Ihnen Flexibilität verleiht, können Sie die häufigsten Einstellungen wiederholen. Warum nicht spezielle Standard-Builder erstellen, die die am häufigsten verwendeten Flags für Sie festlegen? Mit diesen Optionen können Sie weiterhin zusätzliche Flags festlegen. Und für spezielle Fälle könnten Sie das Builder-Muster auf die altmodische Art und Weise verwenden.
Code für einen abstrakten Builder, der alle Einstellungen definiert und das eigentliche Objekt erstellt, könnte etwa so aussehen:
%Vor%Und das wäre der Basis-Builder, der nichts tut:
%Vor% Die Einbeziehung von BaseTableConfigurationBuilder
soll Generika im Code, der den Builder verwendet, vermeiden.
Dann könnten Sie spezialisierte Builder haben:
%Vor%Die Idee ist, dass Sie Builder haben, die die häufigsten Kombinationen von Flags setzen. Sie könnten eine Hierarchie erstellen oder haben keine Vererbungsbeziehung zwischen ihnen, Ihr Anruf.
Dann könntest du deine Erbauer benutzen, um alle Kombinationen zu erstellen, ohne dich selbst zu verstärken. Zum Beispiel würde dies eine filterbare und paginierte Tabellenkonfiguration erzeugen:
%Vor% Und wenn Ihr TableConfiguration
filterbar, paginiert und auch sortierbar sein soll:
Und eine spezielle Tabellenkonfiguration mit einer sehr seltsamen Einstellung, die auch sortierbar ist:
%Vor%Ich würde Ihre Bequemlichkeitsmethoden entfernen, die mehrere Methoden des Builders aufrufen. Der springende Punkt eines solchen flüssigen Builders ist, dass Sie keine Methoden für alle akzeptablen Kombinationen erstellen müssen.
Gibt es eine Methode, die genau das macht, was ich will? (Problem A)
Ja, die Methode, die das tut, was Sie wollen, ist new TableConfigurationBuilder()
. Übrigens, ich denke, es ist sauberer, das Builder-Konstruktorpaket privat zu machen und es über eine statische Methode in TableConfiguration
zugänglich zu machen, dann kannst du einfach TableConfiguration.builder()
aufrufen.
Wenn nicht, welcher ist der nächste, von dem aus zu starten? (Problem B)
Wenn Sie bereits eine Instanz von TableConfiguration
oder TableConfigurationBuilder
haben, kann es sinnvoll sein, sie an den Builder zu übergeben, sodass sie auf der Basis der vorhandenen Instanz vorkonfiguriert wird. Dies ermöglicht Ihnen beispielsweise Folgendes:
Wie wäre es mit einer Konfigurationszeichenfolge ? Auf diese Weise könnten Sie die Tabelleneinstellungen auf eine prägnante, aber dennoch lesbare Art und Weise kodieren.
Als Beispiel wird festgelegt, dass die Tabelle s ortable und r nur ead-only:
ist %Vor%Diese Zeichenfolgen ähneln in gewisser Weise der Befehlszeilenschnittstelle.
Dies könnte für andere Szenarios gelten, die die Wiederverwendung der Tabelle unterstützen. Mit einer Methode, die die Customers-Tabelle erstellt, können wir sie konsistent ändern:
%Vor%Möglicherweise könnte diese DSL sogar verbessert werden, indem man ein Trennzeichen vorlegt, das die set und unset Operationen trennt. Das vorherige Beispiel würde dann folgendermaßen aussehen:
%Vor%Außerdem können diese Konfigurationszeichenfolgen aus Dateien geladen werden, wodurch die Anwendung ohne Neukompilierung konfigurierbar ist.
Wenn ich einem neuen Entwickler helfe, sehe ich den Vorteil in einem gut getrennten Teilproblem, das leicht dokumentiert werden kann.
Annahme: Es gibt wahrscheinlich weniger als 2 ^ (Anzahl der Konfigurationsflags) sinnvolle Konfigurationen für die Tabelle.
Das löst das Problem A: Welches benutzt man? Nun, es gibt jetzt nur eine Handvoll Optionen . Und auch Problem B: Wenn ich etwas Besonderes haben möchte? Nein, wahrscheinlich nicht .
Tags und Links java constructor builder