2016-05-14 13 views
0

ich viele Klassen haben, die jeweils Umsetzung GeneralInterface und möglicherweise zusätzliche funktionale Schnittstellen:Gibt es eine Möglichkeit, Methoden mit nur funktionalen Schnittstellen zu einer zu vereinheitlichen?

interface GeneralInterface {} 

class MyObjectTypeOne implements GeneralInterface { /*...*/} 

class MyObjectTypeTwo implements GeneralInterface, InterOne { /*...*/} 

class MyObjectTypeThr implements GeneralInterface, InterOne, InterTwo { /*...*/} 

Ich habe eine Liste, die diese MyObjectTypeXXX Instanzen

class ListHolder { 

    public static List<GeneralInterface> list = new ArrayList<>(); 

    ListHolder() { 

     list.add(new MyObjectTypeOne()); 
     list.add(new MyObjectTypeTwo()); 
     list.add(new MyObjectTypeTwo()); 
     // add any number of any of the types 
    } 
} 

und 20-40 funktionalen Schnittstellen hält. Hier sind zwei Beispiele:

@FunctionalInterface 
public interface InterOne { 

    boolean onInterOne(); 

    static void iterate() { 

     for (GeneralInterface obj : ListHolder.list) { 
      if (obj instanceof InterOne) { 
       if (((InterOne) obj).onInterOne()) 
        System.out.println("yes"); 
      } 
     } 
    } 
} 

und

@FunctionalInterface 
public interface InterTwo { 

    boolean onInterOne(String string); 

    static void iterate(String string) { 

     for (GeneralInterface obj : ListHolder.list) { 
      if (obj instanceof InterTwo) { 
       if (((InterTwo) obj).onInterTwo(string)) 
        System.out.println("yes"); 
      } 
     } 
    } 
} 

An verschiedenen Stellen im Code muss ich verschiedene iterate Methoden aufrufen:

InterTwo.iterate("S"); 
InterOne.iterate(); 

Mein Problem ist, dass ich das halten iterate Methode für alle funktionalen Schnittstellen, während sie effektiv dasselbe tun: Überprüfen, ob das Objekt diese Schnittstelle implementiert, (Casting) und nur aufrufen abstrakte Methode mit den gegebenen Argumenten.

Gibt es einen Weg, über Syntax oder Design, nur 1 Methode, die das tut? Ich weiß, dass mit Reflexion es eine schlechte Art und Weise ist, dies zu tun (ich bin zeigt es nur um zu zeigen, dass ich meine Forschung tat, ich will es nicht):

static void iterate(Class<?> clazz, Object arg) { 

    for (GeneralInterface obj : ListHolder.list) { 
     if (clazz.isAssignableFrom(obj.getClass())) { 
      Method[] methods = clazz.getMethods(); 
      Method functional; 
      for (Method m : methods) { 
       if (m.getModifiers() == Modifier.ABSTRACT) { 
        functional = m; 
        break; 
       } 
      } 
      if ((boolean) functional.invoke(obj, arg)) // cast arg or do some other trick 
       System.out.println("yes"); 
     } 
    } 
} 
+1

In Ihrem Reflektionsszenario können Sie nur 'Object' Parameter verwenden, so dass es nicht perfekt funktioniert, irre ich mich? Oder fügen Sie der Parameterklasse, die in der funktionalen Methode verwendet wird, einen Cast hinzu. –

+0

@YassinHajaj Über den Reflexionsweg, ja, es wird entweder eine Besetzung im Aufruf oder ein anderer Trick sein. Es ist nicht so wichtig, da es sowieso ein schlechter Weg ist. – user1803551

+0

Können Sie erklären, was Ihr eigentliches Problem ist, das Sie mit einer Reihe von Schnittstellen lösen möchten? Es scheint ein XY-Problem zu sein: http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem – krokodilko

Antwort

0

Ich denke, Ihr Code ein paar Punkte hat das muss verbessert werden, aber ich habe mich nur darauf konzentriert, Ihnen eine Antwort auf Ihr spezifisches Problem zu geben. Ich denke, dass Sie diese gängige Methode zu einem Zwischen abstrakte Klasse übergeben müssen:

abstract class MyObjectTypeAbstract { 
    abstract boolean onInter(String ... testString); 
    abstract boolean onInter(); 
    void iterate(String string) { 

     for (GeneralInterface obj : ListHolder.list) { 
      if (obj instanceof InterTwo) { 
       if (onInter(testString)) 
        System.out.println("yes"); 
      } 
     } 
    } 
    void iterate() { 

     for (GeneralInterface obj : ListHolder.list) { 
      if (obj instanceof InterTwo) { 
       if (onInter()) 
        System.out.println("yes"); 
      } 
     } 
    } 
} 

Was dies tut, ist Ihnen das einzige, was zu machen zu implementieren, die für jeden FunctionalInterface anders zu sein scheint Sie zur Verfügung gestellt. Das ist die onInter Methode. Das scheint anders zu sein. Also habe ich das abstrakt gemacht. Der Rest ist geteilt. Ich habe auch die statische von den iterate-Methoden herausgenommen, so dass sie auf die verschiedenen Implementierungen der onInter-Methode zugreifen können. Hoffentlich brauchst du diese nicht, um statisch zu sein. Also die Lösung, die ich präsentiere ist, um Ihre Klassen zu erweitern diese abstrakte Klasse und implementieren die Schnittstellen wie jetzt.

+1

Meine Objekte erweitern bereits eine Klasse, aber vielleicht kann ich dieses Verhalten darin integrieren. – user1803551

+0

Ich habe das noch einmal gelesen und Sie berücksichtigen nicht, dass es mehrere Interfaces mit demselben abstrakten Methodenargument geben kann. Dies wird die gewünschte Überladung nicht zulassen. Außerdem versuche ich, alle Methoden in derselben Klasse zu vereinen. Siehe http://programmers.stackexchange.com/questions/318164/what-isa-a-good-design-to-couple-relate -Methoden-und-Referenzen. – user1803551

+0

Aber Sie wollen wiederholten Code nicht vermeiden, oder? Zumindest habe ich das versucht. Wenn Sie wirklich eine gute Lösung machen wollen, müssen Sie die statische iterate(), die Sie jetzt haben, loswerden, und Sie müssen die Art und Weise, wie Sie diese Architektur aufgebaut haben, wirklich ändern. Es gibt einfach keine gute Lösung, um Ihren aktuellen Code zu behalten. Wenn Sie eine perfekte Lösung wünschen, die [SOLID] (http://howtodoinjava.com/best-practices/5-class-design-principles-solid-in-java/) Prinzipien folgt, dann müssen Sie aufgeben, was Sie tun haben, zurücksetzen und neu starten. Meine "Lösung" ist nur eine Idee, um es zu umgehen. –