Frage

ich mit einem Protokoll der Ereignisse arbeite, wo es über 60 verschiedene „Typen“ von Ereignissen sind. Jedes Ereignis teilt etwa 10 Objekte, und dann gibt es Unterkategorien von Ereignissen, die verschiedene zusätzliche Eigenschaften teilen.

Wie kann ich mich mit diesen Ereignissen funktioniert auf ihre Art abhängen oder welche kategorisch Schnittstellen sie implementieren.

Aber es scheint Code aufblasen zu führen. Ich habe eine Menge von Redundanz in der Unterklasse Methoden, weil sie zum Teil der gleichen Schnittstellen implementieren.

Ist es angemessen, eine einzige Ereignisklasse mit einer Eigenschaft „type“ zu verwenden und Logik schreiben, die Art überprüft und einige Organisation von Gruppen von Arten zu pflegen (zB eine Liste von Ereignistypen, die Kategorie A, eine zweite Liste, die Kategorie b, usw.)? Oder ist das Unterklasse-Design besser geeignet in diesem Fall?

Erster Ansatz:

public interface Category1 {}
public interface Category2 {}

public abstract class Event {
 private base properties...;
}

public class EventType1 extends Event implements Category1, Category2 {
 private extra properties ...;
}

public class EventType2 extends Event implements Category3, Category4 {
 private extra properties ...;
}

Zweiter Ansatz:

public enum EventType {TYPE1, TYPE2, TYPE3, ...}
public class Event {
 private union of all possible properties;
 private EventType type;
}

Meine persönliche Meinung ist, dass es wie ein einzelnes Ereignis Objekt scheint, ist, was angemessen ist, weil, wenn ich es richtig denke, es gibt keine Notwendigkeit ist die Vererbung für die Verwendung des Modells darzustellen, weil es wirklich nur das Verhalten und meine Bedingungen, die von der Art der Grundlage ändern.

Ich brauche Code zu haben, das Zeug funktioniert wie:

if(event instanceof Category1) {
  ...
}

Das funktioniert gut in den ersten Ansatz, dass anstelle von instanceof kann ich nur auf den Fall, rufen Sie die Methode und „den gleichen Code“ in jedem der entsprechenden Unterklassen implementieren.

Aber der zweite Ansatz ist so viel prägnanter. Dann schreibe ich Sachen wie:

if(CATEGORY1_TYPES.contains(event.getEventType()) {
 ...
}

Und alle meine „Verarbeitungslogik“ kann in einer einzigen Klasse und nichts davon organisiert werden redundant zu den Unterklassen verteilt. Daher ist dies ein Fall, in dem obwohl OO besser geeignet erscheint, wäre es besser nicht sein?

War es hilfreich?

Lösung

Es hängt davon ab, ob jede Art von Veranstaltung von Natur aus unterschiedlichem Verhalten hat, dass das Ereignis selbst ausführen kann.

Haben Ihre Ereignisobjekte Methoden benötigen, die unterschiedlich je nach Art verhalten? Wenn ja, verwendet Vererbung.

Wenn nicht, verwenden Sie eine ENUM den Ereignistyp zu klassifizieren.

Andere Tipps

würde ich mit dem Objekt pro Ereignistyp Lösung gehen, aber ich würde stattdessen Gruppe häufig Kombinationen von Schnittstellen unter (wahrscheinlich abstrakt) Klassen bieten ihre Skelett-Implementierungen . Dies reduziert den Code aufblähen erzeugt durch viele Schnittstellen zu haben, aber auf der anderen Seite erhöht sich die Anzahl der Klassen. Aber, verwendet, wenn sie richtig und vernünftig, es führt zu saubereren Code.

Die Vererbung kann zu begrenzen, wenn Sie eine abstrakte Basisklasse eines entscheiden zu verlängern Insbesondere Kategorie Schnittstelle, da Sie auch eine andere Kategorie implementieren könnte müssen.

So, hier ist eine vorgeschlagene Konzept: Angenommen, Sie müssen die gleiche Implementierung für ein Verfahren bestimmte Kategorie Schnittstelle (unabhängig von der Veranstaltung), könnten Sie eine Implementierungsklasse für jede Kategorie Schnittstelle schreiben.

So müßten Sie:

public class Category1Impl implements Category1 {
    ...
}

public class Category2Impl implements Category2 {
    ...
}

Dann gilt für jede Ihrer Ereignisklassen, geben Sie einfach die Kategorie implementierten Schnittstellen, und halten eine private Mitglied Instanz der Kategorie Implementierungsklasse (so verwenden Sie Zusammensetzung, anstatt Vererbung). Für jede der Kategorie Interface-Methoden, einfach den Methodenaufruf zu der Kategorie Implementierungsklasse übermittelt.

Da ich nicht wirklich die Antworten bekommen habe ich suchte ich meine eigene beste Vermutung bin Bereitstellung basierend auf meiner weniger als wünschenswert Lernerfahrung.

Die Ereignisse selbst Verhaltensweisen nicht wirklich haben, ist es die Handler der Ereignisse, die Verhaltensweisen haben. Die Ereignisse nur das Datenmodell darstellen.

ich den Code neu geschrieben, um nur Ereignisse als Objekt-Arrays von Eigenschaften zu behandeln, so dass ich Javas neue Variable Argumente und Auto-Boxen Funktionen verwenden kann.

Mit dieser Änderung konnte ich rund 100 gigantische Klassen von Code löschen und in etwa 10 Zeilen Code in einer einzigen Klasse viel von der gleichen Logik zu erreichen.

Lektion (en) gelernt: Es ist nicht immer ratsam ist OO Paradigmen auf das Datenmodell anzuwenden. Konzentrieren Sie sich nicht ein perfektes Datenmodell über OO auf der Bereitstellung, wenn sie mit einer großen, variablen Domäne arbeiten. OO-Design profitiert die Steuerung mehr als das Modell manchmal. Konzentrieren Sie sich nicht auch auf die Optimierung im Voraus, da in der Regel eine 10% Leistungsverlust akzeptabel ist und kann über andere Mittel zurückgewonnen werden.

Im Grunde war ich das Problem Over-Engineering. Es stellt sich heraus, ist dies ein Fall, in dem die richtigen OO-Design ist übertrieben und macht aus einem One-Night-Projekt in ein 3-Monats-Projekt. Natürlich muss ich die Dinge auf die harte Tour lernen!

Lediglich eine große Anzahl von .java-Dateien, die ist nicht unbedingt schlecht. Wenn Sie sinnvoll, eine kleine Anzahl (2-4 oder so) von Schnittstellen, die die Verträge der Klassen darstellen extrahieren können, und dann alle der Implementierungen Paket, das API vorhanden Sie können sehr sauber, sogar mit 60-Implementierungen.

Ich könnte auch einige Delegierten oder abstrakte Klassen vorschlagen, mit gemeinsam Funktionalität zu ziehen. Die Delegierten und / oder abstrakte Helfer all Pakete-private oder private Klassen sein sollen, außerhalb der API nicht zur Verfügung aussetzen.

Wenn es erhebliches Mischen und Anpassen des Verhaltens, würde ich mit Zusammensetzung anderer Objekte betrachtet, dann hat entweder den Konstruktor des bestimmten Objekts Ereignistyp diese Objekte erstellen oder einen Builder verwenden, um das Objekt zu erstellen.

vielleicht so etwas wie das?

class EventType {

  protected EventPropertyHandler handler;

  public EventType(EventPropertyHandler h) {
     handler = h;
  }

  void handleEvent(map<String,String> properties) {
    handler.handle(properties);
  }
}

abstract class EventPropertyHandler {
   abstract void handle(map<String, String> properties);
}
class SomeHandler extends EventPropertyHandler {
   void handle(map<String, String> properties) {
      String value = properties.get("somekey");
      // do something with value..
   }
}

class EventBuilder {
   public static EventType buildSomeEventType() {
      // 
      EventType e = new EventType( new SomeHandler() );
   }
}

Es gibt wahrscheinlich einige Verbesserungen, die gemacht werden könnte, aber das könnte Ihnen den Start.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top