Se non si desidera effettuare il refactoring del codice e si può utilizzare Java 8, è possibile utilizzare riferimenti a metodi.
Prima una semplice demo (scusa le classi interne statiche)
public class JavaApplication14
{
static class Baz
{
private final int _int;
public Baz(int value){ _int = value; }
public int getInt(){ return _int; }
}
static class Bar
{
private final Baz _baz;
public Bar(Baz baz){ _baz = baz; }
public Baz getBar(){ return _baz; }
}
static class Foo
{
private final Bar _bar;
public Foo(Bar bar){ _bar = bar; }
public Bar getBar(){ return _bar; }
}
static class WSObject
{
private final Foo _foo;
public WSObject(Foo foo){ _foo = foo; }
public Foo getFoo(){ return _foo; }
}
interface Getter<T, R>
{
R get(T value);
}
static class GetterResult<R>
{
public R result;
public int lastIndex;
}
/**
* @param args the command line arguments
*/
public static void main(String[] args)
{
WSObject wsObject = new WSObject(new Foo(new Bar(new Baz(241))));
WSObject wsObjectNull = new WSObject(new Foo(null));
GetterResult<Integer> intResult
= getterChain(wsObject, WSObject::getFoo, Foo::getBar, Bar::getBar, Baz::getInt);
GetterResult<Integer> intResult2
= getterChain(wsObjectNull, WSObject::getFoo, Foo::getBar, Bar::getBar, Baz::getInt);
System.out.println(intResult.result);
System.out.println(intResult.lastIndex);
System.out.println();
System.out.println(intResult2.result);
System.out.println(intResult2.lastIndex);
// TODO code application logic here
}
public static <R, V1, V2, V3, V4> GetterResult<R>
getterChain(V1 value, Getter<V1, V2> g1, Getter<V2, V3> g2, Getter<V3, V4> g3, Getter<V4, R> g4)
{
GetterResult result = new GetterResult<>();
Object tmp = value;
if (tmp == null)
return result;
tmp = g1.get((V1)tmp);
result.lastIndex++;
if (tmp == null)
return result;
tmp = g2.get((V2)tmp);
result.lastIndex++;
if (tmp == null)
return result;
tmp = g3.get((V3)tmp);
result.lastIndex++;
if (tmp == null)
return result;
tmp = g4.get((V4)tmp);
result.lastIndex++;
result.result = (R)tmp;
return result;
}
}
Produzione
241
4
nullo
2
L'interfaccia Getterè solo un'interfaccia funzionale, puoi usare qualsiasi equivalente.
GetterResultclass, le funzioni di accesso eliminate per chiarezza, mantengono il risultato della catena getter, se presente, o l'indice dell'ultimo getter chiamato.
Il metodo getterChainè un semplice pezzo di codice standard, che può essere generato automaticamente (o manualmente quando necessario).
Ho strutturato il codice in modo che il blocco ripetuto sia evidente.
Questa non è una soluzione perfetta in quanto è ancora necessario definire un sovraccarico di getterChain per numero di getter.
Vorrei invece rifattorizzare il codice, ma se non è possibile e ti ritrovi a usare lunghe catene di getter spesso potresti prendere in considerazione la creazione di una classe con i sovraccarichi che richiedono da 2 a, diciamo, 10, getter.
nulltanto i controlli, poichéwsObject.getFoo().getBar().getBaz().getInt()è già un odore di codice. Leggi cos'è la "Legge di Demetra" e preferisci rifattorizzare il codice di conseguenza. Quindi anche il problema con inullcontrolli sparirà. E pensa di usareOptional.