Wie wird eine generische Aktionsklasse entworfen, während saubere Programmierpraktiken beibehalten werden?

8

Die Aufgabe besteht darin, einen Teil meiner Java-Webanwendung zu erstellen, der es mir ermöglicht, auf einfache Weise kleine Codes in einer zusammengesetzten Weise auszuführen. Die Aufgabe besteht darin, dem Benutzer zu ermöglichen, "Aktionen" in beliebiger Reihenfolge zu erstellen. Worum ich mich bemühe, ist die Weitergabe von Parametern an meine Aktionen.

Alles beginnt mit der Aktionsschnittstelle:

%Vor%

Wenn die Aktion gelöst ist, wird der Code ausgeführt. Der Code kann alles sein: Aufruf einer Methode in Java, Ausführung von Javascript ...

Hier ist der "Kontext" das Problem für mich. Jede Aktion wird in einem bestimmten Kontext ausgeführt. Der Benutzer, der die Aktion erstellt, kann angeben, welches Objekt aus dem Konzept abgerufen werden soll, z. B. der Benutzer, der die aktuelle Aktion auflöst, oder andere Objekte, die in der spezifischen Schnittstelle der Aktion angegeben sind.

Beispiel, schauen wir uns diese Aktion an:

%Vor%

Es ist ein einfacher Wrapper, der eine Aktion in Javascript mit Nashorn aufruft. Die Parameter können alles sein: Objekte mit bestimmten IDs im DB, int / String / boolesche Werte, die vom Benutzer konfiguriert wurden ...

Der Code einer Aktion kann folgendermaßen aussehen:

%Vor%

So kann die Aktion Laufzeitparameter (z. B .: Benutzer, der die Aktion ausführt ...) und statische Parameter (die beim Laden der Aktion erstellt werden - z. B. aus einer Konfigurationsdatei) und alles aus dem Konzept abrufen. Außerdem kann der Benutzer z. B. Verweise auf das Objekt in den Parametern angeben, die zur Laufzeit injiziert werden.

Aktionen können auch verschachtelt / dekoriert werden, um die vollständige Komposition zu erreichen. Zum Beispiel:

%Vor%

Damit können Aktionen leicht erstellt werden:

%Vor%

Wenn Sie all das wissen, was ist am besten geeignet, um die Kontextklasse zu entwerfen? Sollte es in mehrere Elemente aufgeteilt werden? Der Kampf besteht darin, alles, was zur Laufzeit benötigt wird, in die Klasse zu injizieren und sicher zu stellen, dass keine Konflikte mit möglichen eingepackten Aktionen auftreten.

Die grundlegende Implementierung von Context ist verantwortlich für:

  • ruft zur Laufzeit ein beliebiges Objekt aus der Datenbank ab
  • Bereitstellung von statischen Parametern für die Aktionsentwickler, die eine Transaktion halten und
  • geben
  • es Zugang zu dem Benutzer, der Laufzeit und statisches Konzept verschmelzt, und dies sogar in einem Wrapper (zB: wenn eine Elternaktion eine Kindaktion aufruft, Der Benutzer, der die Aktion ausführt, muss noch bekannt sein, damit der Kontext es sein sollte Zusammenführen statischer untergeordneter Parameter und Laufzeitparameter wie z Benutzer)

Ich fühle, dass es zu viel macht. Das Design wird von den Concept-Klassen beeinflusst, die viele Verantwortlichkeiten besitzen und fragmentiert sein sollten (momentan ist jeder Teil der Anwendung mit dem Konzept verbunden). Aber wie ? Hier ist, was ich versuche, saubere Codierung zu erreichen:

  • die Aktionsschnittstelle sollte einfach gehalten werden (1 Methode max, mit a vernünftige Anzahl von Parametern)
  • keine Verwendung von statischen Mechanismen
  • maximale Unveränderbarkeit

In einer objektorientierten Art und methodenorientiert, wie löst man dieses spezifische Designproblem?

edit: entfernt öffentlichen Deklarator in Methode in der Schnittstelle

edit 2: Ich hatte viele interessante Lösungen, aber diejenige, die mir mehr Sinn machte, war diejenige, in der jede Aktion mit einer bestimmten Art von Kontext parametrisiert wird. Ich habe die Dinge als solche neu organisiert:

  • Aktionsschnittstelle hat immer noch nur eine Methode, um die Aktion mit dem Kontext
  • aufzulösen
  • Statische Parameter der Aktionen, seien sie DB oder andere, werden geladen, wenn die Aktion erstellt wird (Benutzersitzung)
  • Der Kontext ist nur eine Fassade für verschiedene Operationen (Transaktion ...) + spezialisierte Operationen, wie der Benutzer der Aktion
MMacphail 05.10.2015, 12:04
quelle

2 Antworten

2

Ich hatte das Action interface generisch auf seinem Context :

gesetzt %Vor%

Und dann könnte Context entweder eine Markierungsschnittstelle, eine Schnittstelle, die einen Vertrag erzwingt, oder eine abstrakte Klasse mit Standardmethodenimplementierungen sein:

%Vor%

Dann könnten Sie tun:

%Vor%

Und ein Action , der den Benutzer anmeldet, könnte sein:

%Vor%

Für einen umschlossenen Action würde ich einen WrapperContext -Kontext verwenden:

%Vor%

Implementierung:

%Vor%

Nun könnte Ihr DummyWrapperAction wie folgt aussehen:

%Vor%

Die Idee besteht darin, auch Kontexte zu umhüllen. Sie können dieses Design verbessern, indem Sie es ermöglichen, Kontexte zu ketten oder zu dekorieren, und abstrakte Klassen verwenden, die für die Aufgaben zuständig sind, die allen Kontexten gemeinsam sind.

    
Federico Peralta Schaffner 05.10.2015, 15:06
quelle
1

Interpreter GoF-Muster, interpretierter Baum kann in gewisser Weise externalisiert werden. Sie können jeden Knoten dekorieren und auf Ihre Anfrage antworten. Noch eine Sache: action interface sollte mindestens zwei Methoden haben, wenn die Repräsentation extern ist (dh vom Benutzer gemacht): eine für die Gültigkeit des Baumes (zB ein Knoten, der zwei Kinder benötigt, muss genau diese Kinder haben) und einen für die Ausführung der Baum.

Bearbeiten: Hier ist ein Beispiel

%Vor%

Ich hoffe, es ist jetzt klar.

    
Radu Dumitriu 05.10.2015 12:58
quelle

Tags und Links