Es ist immer schön, mit einer Anwendung zu sprechen, die sich an Ihre Gewohnheiten erinnert und als ob Sie sich fühlen, was Sie wollen. Jede UI-Bibliothek oder -Plattform verfügt leider nur über grundlegende Funktionen und eine Reihe von Komponenten. Wenn sich beispielsweise eine Spalte in einer Tabelle nicht bewegt oder nicht danach sortiert werden kann, kann eine solche Anwendung, in der sie verwendet wird, kaum als freundlich bezeichnet werden. Glücklicherweise werden Sie heute niemanden mit solchen Funktionen überraschen. Nicht jedes Programm merkt sich jedoch die Position dieser Spalte und zeigt sie in der nächsten Sitzung an derselben Stelle an. Es kann auch ärgerlich sein, die Position des Trennzeichens jedes Mal in SplitPane festzulegen oder dieselben Filterparameter einzugeben. Solche Annehmlichkeiten müssen in der Regel von den Entwicklern selbst bereitgestellt werden.
Es gibt viele Beispiele für solche scheinbar kleinen Verbesserungen, aber die von der Plattform angebotenen Lösungen sind nur zwei und im Wesentlichen ähnlich: Erstellen Sie Ihre eigene Komponente basierend auf der Basis, erstellen Sie Ihre Skin für die Basiskomponente und definieren Sie das Verhalten neu. Keine dieser Methoden ist einfach zu implementieren, außerdem muss jede Komponente ihre eigene Adapterkomponente schreiben. Ich habe einige Leute getroffen, denen diese Methode vertrauter und verständlicher war.
Aber er ist weit davon entfernt, der Einzige zu sein. Was ist, wenn wir die Funktionen der Plattform nutzen, die die Browservorlage für den untergeordneten Knoten unterstützt , und beim Hinzufügen oder Entfernen des Knoten- Untergraphen eine Reihe von Plugins ausführen, von denen jedes seine eigene spezifische Arbeit ausführt? Einer kann sich während einer zweiten Sitzung alles merken und wiederherstellen, der andere - die angegebenen Komponenten werden über das Kontextmenü geändert, wodurch die Funktion zum Kopieren von Text hinzugefügt wird. Einige von ihnen fügen drei Punkte am Ende des Textes hinzu, wenn er nicht passt. Wenn Sie mit der Maus über die Maus fahren, wird nur dann ein Hinweis mit Volltext angezeigt, wenn er nicht passt. Vor allem spielt es keine Rolle, aus welcher Bibliothek diese Komponente stammt, ob wir davon erben und das benötigte Verhalten neu definieren können. In diesem Fall müssen wir dem Plugin lediglich beibringen, bei Bedarf auf unterschiedliche Weise mit den erforderlichen Komponenten zu arbeiten.
Dies könnte ein Zuhörer für eine Sammlung von Kindern sein:
private final ListChangeListener changeListener = (ListChangeListener<Node>) (ListChangeListener.Change<? extends Node> c) -> { if (c.next()) { c.getAddedSubList().forEach(this::applySettingsForNodeAndAddListenerForItsChild); } };
Das wäre der Verarbeitungscode für jeden geänderten Knoten :
private void applySettingsForNodeAndAddListenerForItsChild(Node n) { if (!checkApplySettings(n)) { apply(n); ObservableList<Node> children = getChildren(n); if (children != null) { addListnerForUpdateChildren(children); } markNodePropertyApplied(n); } }
Und so lautet der Code, der direkt das Plugin selbst aufruft, das für diesen Komponententyp registriert ist:
public Node apply(Node node) { List<SettingsPlugin> settingsPlugins = settingsMap.get(Node.class); if (settingsPlugins != null) { for (SettingsPlugin plugin : settingsPlugins) { node = plugin.apply(node, userSettings.getSettings()); } } List<SettingsPlugin> settingList = settingsMap.get(node.getClass()); if (settingList != null) { for (SettingsPlugin plugin : settingList) { node = plugin.apply(node, userSettings.getSettings()); } } return node; }
Hier ist die Schnittstelle des Plugins selbst:
public interface SettingsPlugin { public Node apply(Node node, Map<String, Object> userSettings); }
Es ist nur erforderlich, den Listener einmal in der Sammlung der untergeordneten Root- Elemente des Scene- Elements zu registrieren, und im Rest des Untergraphen wird er sich selbst registrieren ...
Kürzlich habe ich eine Analogie zu den Funktionen von Plattformen für Desktop- und Webanwendungen gezogen. Es wäre interessant zu wissen, wie solche Funktionen auf verschiedenen Frameworks implementiert werden können.