2015-11-06 5 views
8

Sto cercando di creare un particolare tipo di interfaccia in Java (anche se questo è applicabile alle classi regolari). Questa interfaccia dovrebbe contenere un metodo, per esempio, invoke; sarebbe chiamato con una quantità variabile di parametri a seconda degli argomenti di tipo generico forniti.In Java, posso specificare qualsiasi quantità di parametri di tipo generico?

Per fare un esempio:

public interface Foo<T...> { 
    public void invoke(T... args); 
} 

// In some other class 
public static Foo<Float, String, Integer> bar = new Foo<Float, String, Integer>() { 
    @Override 
    public void invoke(Float arg1, String arg2, Integer arg3) { 
     // Do whatever 
    } 
}; 

di spiegare, in breve, come questo potrebbe essere utilizzato (e fornire alcuni contesto), prendere in considerazione una classe Delegator: la classe prende un numero variabile di tipi generici, e ha un unico metodo - invoke, con questi tipi di parametri. Il metodo passa i suoi parametri a un oggetto in un elenco: un'istanza di IDelegate, che accetta gli stessi tipi generici. Ciò consente a Delegator di scegliere tra diversi metodi delegati (definiti all'interno di IDelegate) senza dover creare una nuova classe per ogni elenco specifico di tipi di parametri.

È disponibile qualcosa di simile? Ho letto su variadic templates in C++, ma non riesco a trovare nulla di simile in Java. Qualcosa del genere è disponibile? In caso contrario, quale sarebbe il modo più pulito per emulare lo stesso modello di dati?

risposta

4

È disponibile qualcosa di simile? Ho letto sui modelli variadici in C++, ma non riesco a trovare nulla di simile in Java. È disponibile una cosa del genere ?

No, questa funzione non è disponibile in Java.

2

No, non c'è niente di simile direttamente disponibile. Tuttavia, se si utilizza una biblioteca con Tuple classi è possibile simulare il programma semplicemente rendendo l'interfaccia

interface Foo<T> { 
    void invoke(T t); 
} 

(Questa interfaccia è sostanzialmente la stessa di Consumer<T>.)

allora si potrebbe fare per esempio

Foo<Tuple<String, Integer, Date, Long>> foo = new Foo<>() { 
    ... 
} 

Per ciascun numero di parametri è necessario un tipo Tuple separato. Se si dispone di una classe Tuple per 4 parametri, ma non di una per 5, è possibile comprimere un parametro aggiuntivo utilizzando una classe Pair.

Foo<Tuple<String, Integer, Date, Pair<Long, BigDecimal>>> foo = ... 

Nidificando i tipi di tupla in questo modo si ottiene un numero illimitato di parametri. Tuttavia, questi workaround sono davvero brutti e non li userei.

+0

Per dirla in questo modo: 'Coppia ' sarebbe sufficiente. Ma dal momento che nessuno vuole un 'paio >>>', le cose di questo tipo vengono solitamente risolte in modo diverso. O eliminando del tutto la sicurezza del tipo o con le librerie come http://www.javatuples.org/ – Marco13

2

Dato il contesto che hai fornito, ti consiglio di utilizzare un parametro List. Se questi parametri hanno qualcosa in comune, puoi limitare il tuo elenco a <T extends CommonParrent> invece di utilizzare List<Object>. In caso contrario, potresti comunque voler utilizzare l'interfaccia marker.

Ecco un esempio.

public class Main { 

    public static void main(String[] args) { 
     delegate(asList(new ChildOne(1), new ChildTwo(5), new ChildOne(15))); 
    } 

    private static <T extends Parent> void delegate(List<T> list) { 
     list.forEach(item -> { 
      switch (item.type) { 
       case ONE: delegateOne((ChildOne) item); break; 
       case TWO: delegateTwo((ChildTwo) item); break; 
       default: throw new UnsupportedOperationException("Type not supported: " + item.type); 
      } 
     }); 
    } 

    private static void delegateOne(ChildOne childOne) { 
     System.out.println("child one: x=" + childOne.x); 
    } 

    private static void delegateTwo(ChildTwo childTwo) { 
     System.out.println("child two: abc=" + childTwo.abc); 
    } 

} 

public class Parent { 
    public final Type type; 

    public Parent(Type type) { 
     this.type = type; 
    } 
} 

public enum Type { 
    ONE, TWO 
} 

public class ChildOne extends Parent { 
    public final int x; 

    public ChildOne(int x) { 
     super(Type.ONE); 
     this.x = x; 
    } 
} 

public class ChildTwo extends Parent { 
    public final int abc; 

    public ChildTwo(int abc) { 
     super(Type.TWO); 
     this.abc = abc; 
    } 
} 

Il più grande difetto di questa soluzione è che i bambini devono specificare il loro tipo tramite enum che dovrebbe corrispondere ai calchi in l'istruzione switch, in modo ogni volta che si cambia uno di questi due posti, si dovrà ricordarsi di cambia l'altro, perché il compilatore non ti dirà questo. Troverai tale errore solo eseguendo il codice ed eseguendo un ramo specifico in modo da consigliare lo sviluppo guidato dai test.

Problemi correlati