Problem - evtl mit Generics lösbar

acky

Mitglied
Hallo,

ich habe folgende Situation:


Klasse x = new Klasse(); // Klasse ausserhalb meines Scopes

A_Request aIn = new A_Request();
A_Respone aOut = x.handle(aIn); // überladen

B_Request bIn = new B_Request();
B_Respone bOut = x.handle(bIn); // überladen
...

Diese Aufrufe würde ich gerne über eine Methode laufen lassen.
private ResponseType handle(RequestType request) {
return x.handle(request);
}

Kann ich irgendwie erreichen, dass diese Methode als Parameter A_Request ... Z_Request entgegennimmt,
und mit entsprechendem Response-Typ antwortet? (Die x.handle-Methode nimmt nur konkrete Request-Objekte an!)

Danke im Voraus,
Acky
 
Zuletzt bearbeitet:
Und was ist genau die Frage?

Wenn handle bestimmte Methoden von den Requests braucht, mach doch ein Interface und bind das ein.

Gruß
 
Die Klasse, die diese Methode 'handle' hat,sowie alle verschiedenen Request- und Response-Klassen liegen nicht unter meiner Kontrolle. Somit akzeptiert die handle-Methode auch nur konkrete Requests.

Acky
 
Wenn du weder Request, Response noch die handle-Klasse ändern kannst, was willst du dann überhaupt machen?

Ich versteh dein Problem noch immer nicht.

Wenn du nichts ändern kannst, wozu überlegst du dann, wie man es machen könnte?

edit: Falls du nur die restliche Klasse von handle gemeint hast, die Methode handle aber schon ändern darfst:
Haben die Requests und Responses jetzt irgendwas gemeinsam oder willst du jede Art getrennt behandeln (und alles eben "handle" nennen?)

Wenn sie Gemeinsamkeiten habend, und kein Interface dazugeschrieben werden darf/kann, fällt mir nur noch der Weg über Reflections ein.
Damit kannst du jedes Object untersuchen, welches Obekt von welcher Klasse es ist, wovon es erbt, welche Methoden (samt Parameter) es hat etc...

Gruß
 
Zuletzt bearbeitet:
Ich würde gerne eine Klasse M (unter meiner Kontrolle) haben, die eine Instanz dieser Klasse x hat und zentral die 'handle()'-Methode kapselt. Ich rufe also jeweils 'm.handle()' auf, womit 'x.handle()' aufgerufen wird.

Diese Methode in M nimmt also alle und nur konkrete(!) Request-Objekte als Parameter an - und gibt entsprechende Response zurück. Die Request-Objekte haben zwar eine gemeinsame Superklasse. Zur Compile-Zeit wird die Superklasse jedoch ja nicht als passender Parameter erkannt, da 'x.hanlde()' ja nur eben konkrete Requests kennt.

Meine Frage:
Gibt es da eine Möglichkeit, dass ich
a) via Generics klarmachen kann, dass in m.handle() konkrete Requests ankommen ... und ich eine entsprechende Response (wiederum konkreten Typs) zurückgeben kann - oder
b) ein Pattern, mit dem ich erreichen kann, dass ich mit wenig Code diese Aufrufe zentralisieren kann?

Danke,
Acky
 
Also, Problem 1: Klassen übergeben, die von einer bestimmten Superklasse abgeleitet sind, aber nicht die Superklasse selber.

Solange du an den Klassen nichts verändern darfst, würde ich einmal sagen, dass es zur Compilezeit nicht geht.
Ich kann nur nocheinmal auf die Reflections verweisen. Damit kann man zur Laufzeit Objekte untersuchen, uA auch wovon sie abgeleitet sind.
(Ich habs zwar bisher nur in C#, aber noch nie in Java verwendet. Bin mir aber ziemlich sicher, dass Java die gleichen Möglichkeiten bietet, nur mit anderen Methoden-/Klassen-namen)

Problem2: Anhand eines Klassennamen ein Objekt einer bestimmten anderen Klasse erstellen, ohne für jede Möglichkeit ein if schreiben.
Auch hier Reflections. Du holst dir den Klassennamen des Requests, nimmst den ersten Buchstaben, hängst "_Response" dran, und hast damit den Klassennamen vom Response.
Wenn du den Namen hast, kannst du damit wieder ein Objekt erstellen.

Gruß
 
Danke!

Ich habe da noch eine interessante Feststellung, die mir nicht ganz klar ist.

GEHT:
public <IN extends A_Request, OUT extends Response> Response process(IN request) {
return x.process(request);
}

GEHT NICHT:
public <IN extends A_Request, OUT extends Response> OUT process(IN request) {
return x.process(request);
}

Der Rückgabewert ist also generell vom Typ 'Response' - und obwohl OUT 'extends' Typ Response
und ich die Methode wie folgt aufrufe:
'processor.<A_Request, A_Response>process(request)',
sagt der Compiler: cannot cast for A_Response to OUT.

Geht da nicht noch was?! Danke!
Acky
 
Ähm... habt ihr schon mal über Methoden-Überladung nachgedacht? Ich blicke hier zwar nicht ganz durch, aber mir scheint, das wäre eine mögliche Lösung.
 
Hallo,

wie wärs denn damit?
Java:
package de.tutorials.training;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class ReqResExample {

  public static void main(String[] args) {
    Handler h = new Handler(new X());

    System.out.println(h.handle(new AReq()));
    System.out.println(h.handle(new BReq()));

  }

  static class Handler {
    private X x;

    private Map<Class<?>, Method> handlerMethods = new HashMap<Class<?>, Method>();

    public Handler(X x) {
      this.x = x;
      for (Method m : this.x.getClass().getDeclaredMethods()) {
        Class<?>[] paramTypes = m.getParameterTypes();
        if ("handle".equals(m.getName()) && paramTypes.length == 1 && Req.class.isAssignableFrom(paramTypes[0])) {
          m.setAccessible(true);
          handlerMethods.put(paramTypes[0], m);
        }
      }
    }


    public Res handle(Req req) {
      Object result = null;
      if (handlerMethods.containsKey(req.getClass())) {
        try {
          result = handlerMethods.get(req.getClass()).invoke(x, req);
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
      return Res.class.cast(result);
    }
  }

  static class X {
    public ARes handle(AReq req) {
      return new ARes();
    }

    public BRes handle(BReq req) {
      return new BRes();
    }
  }

  static class Req {}
  static class Res {}

  static class AReq extends Req {}
  static class ARes extends Res {}

  static class BReq extends Req {}
  static class BRes extends Res {}
}

Ausgabe:
Code:
de.tutorials.training.ReqResExample$ARes@45bab50a
de.tutorials.training.ReqResExample$BRes@64c3c749

Gruß Tom
 
Zurück