Redundantes statisches Verhalten in Klassen

Ich habe drei Klassen:


   public static enum Type {ONE, TWO;}
   
   protected Object attribute;

  //...
}

public class SubClass1 extends SuberClass{

   private static final Map<String, Object> map = new HashMap<String, Object>();
   static{
      add(Type.ONE, Integer.valueOf(1));
      add(Type.TWO, Integer.valueOf(2));
   }

   // ...

   public void doStuff(String key){
     this.attribute = map.get(key);
   }
}

public class SubClass2 extends SuberClass{

   private static final Map<String, Object> map = new HashMap<String, Object>();
   static{
      add(Type.ONE, Integer.valueOf(10));
      add(Type.TWO, Integer.valueOf(20));
   }

   // ...

   public void doStuff(String key){
     this.attribute = map.get(key);
   }```

In beiden Klassen wird eine statische Map angelegt (Da Key-Value-Paare für alle Instanzen der Klasse identisch sind). Pro Instanz möchte ich die Map nicht anlegen, da ich ja nur immer einen Wert daraus für jede Instanz benötige. Zudem sind die Werte unveränderlich und haben keinen direkten Bezug zu den Klassen.
Die Schlüssel in jedem Subtyp sind dieselben, nur die Werte unterscheiden sich. Je nach erbender Klasse.

Jetzt meine Frage: Gibt es irgendeinen eleganten Weg, das in die gemeinsame Super-Klasse auszulagern!? Denn ich jedem Subtyp die map und die Methode "doStuff" zu wiederholen scheint mir nicht sehr unschöne und aufwendige Lösung zu sein.

Sieht sehr abenteuerlich aus, was wäre denn ein Anwendungsfall davon?

Wenn es nur darum geht den String reinzukriegen und ein enum mit Wert herauszubekommen könntest du dem Wert auch einfach ein privates Feld geben und dann sowas schreiben wie
Type.valueOf(String).getValue();

Gruß

ist doch klassisch
[spoiler]``` public class SuperClass {

   public static enum Type {ONE, TWO;}
   
   protected Object attribute;
 
  //...
}
 
public class SubClass1 extends SuberClass{
   // ...
   public void doStuff(String key){
     this.attribute = Type.valueOf(key).ordinal();
   }
}
 
public class SubClass2 extends SuberClass{
 // ...
 
   public void doStuff(String key){
     this.attribute = Type.valueOf(key).ordinal()*10;
   }```[/spoiler]

bye
TT

Vorsicht mit der verwendung von ordinal, ändert man später im Enum die Reihenfolge der Elemente oder fügt neue Elemente nicht am Ende, ein zerhaut man sich im worst-case den kompletten alten Code.

Gruß

[QUOTE=Firephoenix]Vorsicht mit der verwendung von ordinal, ändert man später im Enum die Reihenfolge der Elemente oder fügt neue Elemente nicht am Ende, ein zerhaut man sich im worst-case den kompletten alten Code.[/QUOTE]Das ist im Prinzip richtig, aber wie wahrscheinlich ist es, dass Zahlworte umsortiert werden?

bye
TT

[QUOTE=Timothy_Truckle;29889]Das ist im Prinzip richtig, aber wie wahrscheinlich ist es, dass Zahlworte umsortiert werden?

bye
TT[/QUOTE]
siehe: Bloch - effective java

im Sinne von “Sag niemals nie”

Den wollte ich auch grad rausholen :wink:

Auf mich wirkt es aber, als ob da noch ein Designproblem vorliegt. Du sagst selbst, dass die Werte eigentlich keinen Bezug zur Klasse haben. Warum sind sie dann darin?
Vielleicht solltest du die Enums etwas erweitern, sodass sie die Aufgabe erfüllen, die sie zu erfüllen haben?
Mir ist noch nicht 100%ig klar, was genau erreicht werden soll, daher kann ich nichts konkreteres sagen.
Wenn die eine Klasse beispielsweise den Wert des Enums nur mit 10 multipliziert, dann verpasse den Enums einen Konstruktor, der ONE eine 1 und TWO eine 2 zuweist. Mit einem Getter holst du dann den Wert und multiplizierst ihn in der SubClass mit 10, bzw gibst ihn unverändert zurück. Als Parameter kommt nicht mehr der String, sondern gleich der ganze Enum rein.

:wut: Natürlich bekommt die Methode doStuff als Übergabe-Parameter das Enum, und nicht einen String. -.- Freitag Abend “mal eben noch schnell posten” sollte ich mir wohl abgewöhnen. Sorry für die Verwirrung.:culpability:

   public static enum Type {ONE, TWO;}
   
   protected Object attribute;
   //...
}

public class SubClass1 extends SuberClass{
   private static final Map<String, Object> map = new HashMap<String, Object>();
   static{
      add(Type.ONE, Integer.valueOf(1));
      add(Type.TWO, Integer.valueOf(2));
   }
   // ...
   public void doStuff(Type key){ // <-- Hier das Enum
     this.attribute = map.get(key);
   }
}

public class SubClass2 extends SuberClass{
   private static final Map<String, Object> map = new HashMap<String, Object>();
   static{
      add(Type.ONE, Integer.valueOf(10));
      add(Type.TWO, Integer.valueOf(20));
   }
   // ...
   public void doStuff(Type key){ // <--- Hier das Enum
     this.attribute = map.get(key);
   }```

Ich meinte das eher so:

    public static enum Type {
        ONE(1), TWO(2);
        private int value;
        Type(int value) { this.value = value; }
        public int value() { return value; }
    }

    protected Object attribute;
    public abstract void doStuff(Type type);
}

public class SubClass1 extends SuperClass {
    public void doStuff(Type type) {
        attribute = type.value();
    }
}

public class SubClass2 extends SuperClass {
    public void doStuff(Type type) {
        attribute = type.value() * 10;
    }
}```

Ja, da hättest du Recht, aber statt einfach nur Zahlen zu speichern, sind es eigentlich Objekte. Da habe ich wohl etwas zu viel “für das Forum vereinfacht”. Und diese kann ich leider auch nicht auseinander berechnen.

So kommt der Code etwas näher an mein Problem:

public class SubClass1 extends SuberClass{
  private static final Map<String, MyInterface> map = new HashMap<>();
  static{
    add(Type.ONE, new MyInterfaceImpl1());
    add(Type.TWO, new MyInterfaceImpl2());
  }
 //...```

Warum übergibst du nicht direkt MyInterface, bzw im konkreten Fall dann MyInterfaceImpl1/2?
Das sieht für mich ziemlich nach dem Strategy-Pattern aus.

Gruß

Im Prinzip schon. Allerdings sind die wählbaren “Strategien” pro Subklasse eben unterschiedlich. Daher möchte ich das Verhalten von außen nur über das Enum setzen lassen, und die konkrete Implementierung lieber verbergen.

Vielleicht passt die Implementierung dann in den Enum selbst? Du kannst dem Enum doch eine
Map<Class<?>, MyInterface>
verpassen und dann mit
public MyInterface getStrategy(Class<?> clazz);
die Strategie holen.

Wobei sich diese Lösung schon ein wenig komisch “anfühlt”, weil das Enum dafür ja vorher initialisiert werden muss…

Dann hätte ich das verhalten ja je SubClasse im Enum abgebildet… Würde schon gerne alles was zu SubClass1 gehört auch irgendwie in SubClass1 verwalten…

Ich denke die einfachste Lösung wird es sein, wenn ich die implemtierende SubKlasse mit übergebe und aus SubClass + Type einen eindeutigen Key generiere, mit dem ich in einer statischen map der Superklasse die jeweilige Interface-Instanz nachschlagen kann.