2015-01-28 5 views
6

Ho una classe Java astratta "BaseOperation". Questa classe ha un solo metodo astratto:Un metodo java con tipo di ritorno variabile e argomenti di input variabili

public abstract T execute() 
{ 
    ... 

    return T; 
} 

sottoclassi di BaseOperation deve implementare questo metodo:

public class GetUsersOperation extends BaseOperation<GetUsersResponse> 
{ 
    ... 

    @Override 
    public GetUsersResponse execute() 
    { 

     ... 

     return GetUsersResponse; 
    } 

} 

Questo è un ottimo modo per mettere tutti comuni logica "operazione" nella classe BaseOperation, ma avere ancora il metodo execute() della sottoclasse in calcestruzzo con un tipo di restituzione diverso.

Ora ho bisogno di cambiare questa struttura per consentire ai metodi execute() di avere una quantità variabile di argomenti. Per esempio, una sottoclasse concreta richiederebbe:

execute(String, int) 

e un altro avrebbe bisogno:

execute(Date, Date, String) 

Questo è difficile, perché il metodo execute viene dichiarato nella classe base. Semplicemente sovraccaricare i metodi di esecuzione nella base non è l'ideale. In primo luogo, la quantità di sovraccarichi sarebbe enorme. In secondo luogo, ogni sottoclasse utilizzerà sempre solo uno dei metodi di esecuzione, qual è il punto di tutti gli altri?

L'(a mio parere) soluzione più semplice sarebbe quella di dichiarare il metodo execute con varargs:

execute(Object... arguments) 

E poi downcast tutti gli argomenti nelle sottoclassi:

execute(Object... arguments) 
{ 
    String s = (String) arguments[0]; 
    ... 
} 

Ovviamente questo ha 2 principali Svantaggi:

  • Prestazioni ridotte a causa di tutte le operazioni downcasting
  • La chiamata dei metodi execute() non è più strettamente immessa perché è possibile passare qualsiasi quantità di oggetti senza avvisi del compilatore.

Esistono modelli o altre soluzioni che potrebbero non avere questi svantaggi?

risposta

2

Come già detto, l'approccio comune per risolvere il problema è l'utilizzo di parametri di mantenimento dei bean.Ma qui è un'altra soluzione, basata su un approccio costruttore:

public interface BaseOperation<T> { 
    public T execute(); 
} 

public class AddOperation implements BaseOperation<Integer> { 
    private int a, b; 

    public void setA(int arg){ 
    a = arg ; 
    return this; 
    } 

    public void setB(int arg){ 
    b = arg; 
    return this; 
    } 

    @Override 
    public Integer execute() { 
    return a+b ; 
    } 
} 

E poi usare in questo modo:

new AddOperation().setA(1).setB(2).execute(); 

È possibile miscelazione desiderata e parametri opzionali in questo modo:

public class MultipleAddOperation implements BaseOperation<Integer> { 
    private int sum ; 

    public MultipleAddOperation(int requiredInt){ 
    sum = requiredInt; 
    } 

    public void add(int optionalInt){ 
    sum += optionalInt ; 
    return this; 
    } 

    @Override 
    public Integer execute(){ 
    return sum; 
    } 
} 

E così:

new MultipleAddOperation(5).add(1).add(2).execute(); 
+0

Mi piace come la logica relativa all'input richiesto sia codificata come attributi (campi) della sottoclasse stessa (con i metodi set necessari), piuttosto che come una classe bean separata. Tuttavia, non c'è nulla che mi impedisce di chiamare execute() senza aver impostato i parametri appropriati. Questo può essere risolto? – user1884155

+0

@ user1884155 Sì, passare argomento nel costruttore di operazioni, vedere la mia modifica;) – NiziL

+0

Ah, ovviamente. Preferisco questa soluzione rispetto alla "semplice" soluzione javabean perché sono richiesti tutti i miei parametri e non voglio introdurre una classe bean aggiuntiva per ogni classe di operazioni che creo. Grazie! – user1884155

5

si potrebbe usare un fagiolo tenendo i parametri:

public interface BaseOperation<T, U> { 
    T execute(U input); 
} 

public class GetUsersOperation implements BaseOperation<GetUsersResponse, UserInput> { 

    @Override 
    public GetUsersResponse execute(UserInput input) { 
     Date date = input.getDate(); 
     return new GetUsersResponse(date); 
    } 

} 

tua classe astratta ha solo un unico metodo astratto: meglio usare un'interfaccia. È possibile implementare diverse interfacce mentre è possibile estendere solo una classe.

+0

Grazie per il pr ompt risposta La mia classe base ha altri metodi, ma ha solo 1 metodo PUBLIC. Tutti gli altri metodi privati ​​/ protetti non sono astratti e fanno il lavoro comune come la registrazione, l'analisi dei messaggi, ecc. Le interfacce non possono avere il codice effettivo in java 1.7, quindi penso che non sia possibile girarlo in un'interfaccia. O mi sbaglio su questo argomento? – user1884155

+0

@ user1884155 No, hai ragione, pensavo che avesse un solo metodo astratto. – sp00m

+1

Sei curioso di sapere perché preferirei un bean piuttosto che una classe con più costruttori? Con i costruttori sovraccaricati, è possibile evitare tutte le linee aggiuntive che impostano i parametri e fornire inoltre indicazioni su combinazioni di parametri accettabili e valori richiesti. – Blegger