Diciamo che ho 2 classi: Foo
e Bar
.
'Foo' {
List<Bar> bars
String bippy()
int boop()
}
'Bar' {
int biz()
String baz()
}
Osserva che i campi di Foo
includono List<Bar>
. Tieni presente che Foo
ha campi separati da Bar
, ma condividono alcuni campi.
Diciamo che ho un metodo, f
.
def f(Foo foo) {
...
}
Questo metodo, f
, attualmente accetta solo un tipo Foo
. Tuttavia, questo metodo richiede anche l'accesso a Bar
.
Quando ho bisogno di passare un Bar
, potrei semplicemente creare un nuovo Foo
con un singolo Bar
in List<Bar>
- ma non mi piace questa ipotesi. Inserire questo assunto nel codice non sarà (e non dovrebbe essere) facilmente comprensibile dall'utente.
Quindi, ho deciso di creare un'interfaccia, Something
, implementata da entrambe le classi:
interface Something {
Optional<String> getBippy()
Optional<int> getBoop()
Optional<int> getBiz()
Optional<String> getBaz()
}
Con questa interfaccia, ora posso aggiornare l'argomento di f
in modo che sia di tipo Something
.
Come risultato di questa nuova interfaccia, le implementazioni di Foo
e Bar
restituiranno valori "mancanti" se la classe di implementazione non riesce ad avere il campo previsto nell'interfaccia.
Esempio:
Foo implements Something {
List<Bar> bars
getBippy() { return bippy }
getBaz() { return None }
... // remaining implementations
}
Questo approccio funzionerà, credo, a condizione che lo sviluppatore che utilizza il metodo f
passi nel tipo corretto.
Come è il mio approccio? In particolare, sono curioso di sapere se esiste un approccio di tipo / staticamente sicuro.