Sostituzione per esempio di Java?


10

Quindi sono abbastanza nuovo nella programmazione nel mondo reale (al di fuori dei progetti accademici) e mi sono imbattuto in molti post che affermano che usare instanceofè una cosa negativa da usare per determinare quale classe è un oggetto specifico.

La mia situazione è che ho tre classi, una classe di prodotto di base, una che si estende da quella e un'altra che si estende da quella. Questi sono tutti memorizzati nella stessa tabella in un database e ho del codice che deve utilizzare i metodi su ciascuno per estrarre i dati da essi.

Qual è la migliore pratica per aggirare questo modo di farlo? Ho letto alcune cose sul polimorfismo ma non riesco a trovare alcun esempio che risolva il problema che ho. Di solito tutti hanno la precedenza su un metodo che per me non funzionerà perché devo estrarre cose diverse dai diversi oggetti.

C'è un modo migliore per farlo o sono bloccato con l'uso instanceofo una sorta di riflessione per ottenere i campi specifici degli oggetti?


10
Non è che la parola chiave instanceofsia sbagliata; cercare di trovare la classe di un oggetto è di solito il problema. Non sempre sbagliato, ma probabilmente nel tuo caso lo è. Forse se ci dici cosa stai cercando di realizzare, possiamo suggerire una soluzione usando il polimorfismo.
Andres F.

2
Va bene, ogni classe ha dati specifici ad essa. Voglio estrarre i dati specifici da questi. Penso di aver realizzato la risposta con l'aiuto che ho avuto. Qualcosa come un metodo chiamato getSpecifics()che è implementato in modo diverso su ciascuno, con ognuno che restituisce i dati specifici della classe?
Thomas Mitchell,

Risposte:


16

Il motivo instanceofè scoraggiato è che non è OOP.

Non ci dovrebbero essere motivi per cui il chiamante / utente di un oggetto sappia quale classe concreta è un'istanza oltre il quale tipo la variabile viene dichiarata.

Se hai bisogno di comportamenti diversi nelle sottoclassi aggiungi un metodo e implementali in modo diverso.


1
Quindi un metodo getSpecifics()(o qualcosa di simile) su ogni classe che restituirà i dettagli per ogni classe. È questo l'approccio migliore?
Thomas Mitchell,

@Schmooo Devi davvero pensare a dove esiste la funzionalità comune all'interno dell'albero delle classi e quali contratti esistono ad ogni livello.

3
Ma che dire di un caso in cui l'oggetto attraversa i livelli e le informazioni sul tipo vengono perse? Esempio, creo a List. Lo passo a un oggetto che ne prende uno Iterable. Ora quel secondo oggetto lo passa a un terzo oggetto che accetta o Listper l'ottimizzazione, o Iterablema è molto più lento. Il secondo non dovrebbe sapere che è un elenco, ma il terzo vorrebbe molto saperlo. Il terzo oggetto non dovrebbe verificare ad esempioof per vedere se può applicare l'ottimizzazione? Vedi ad esempio la guava FluentIterableche fa proprio questo.
Laurent Bourgault-Roy,

1
Direi che non è sempre il caso che devi aggiungere il metodo alla classe. Ad esempio, alcuni codici ottengono un'eccezione e si suppone che facciano qualcosa a seconda del tipo. Dire, fare una segnalazione o fare qualcosa per recuperare da errori. Questo tipo di funzionalità sicuramente non soddisfa le eccezioni. Oppure, se le classi provengono da alcune librerie esterne, non hai nemmeno i mezzi per modificarle. In questo caso penso che sia assolutamente valido fare affidamento sul instanceof.
Malcolm,

9

instanceof non è necessariamente una brutta cosa, tuttavia è qualcosa che si dovrebbe guardare.

Un esempio di dove funziona correttamente è in un posto in cui si ottiene una raccolta del tipo di base e si desidera solo quelli di un sottotipo. Recuperare gli indirizzi di rete NetworkInterface.getNetworkInterfaces()restituisce gli oggetti NetworkInterface che hanno una raccolta di oggetti InetAddress, alcuni dei quali sono Inet4Address e altri sono Inet6Address. Se si desidera filtrare la raccolta per gli oggetti Inet4Address, è necessario utilizzare instanceof.

Nella situazione descritta nel post originale, esiste una classe Base, qualcosa che estende quella classe base e qualcosa che estende la classe estesa. Anche se non completamente informativo, questo sembra avere le basi di un design tutt'altro che ideale.

Quando si restituisce una classe di base a meno che non vi siano buone ragioni per essere stata progettata in questo modo (compatibilità all'indietro tra le specifiche di una versione precedente), non si dovrebbe tentare di sbirciare i tipi sottostanti. Se ti viene restituito un set, sai che stai ottenendo un set. Consente allo sviluppatore di cambiare idea in seguito per restituire un tipo più specifico (SortedSet) o modificare il tipo sottostante (HashSet in TreeSet) senza interrompere nulla.

Riconsidera il tuo progetto su come gli oggetti sono strutturati e genitoriali per vedere se uno può creare un modello di classe migliore che non richiede una distinzione di tipi.


È possibile che avere l'interfaccia specifica un isOfType(SomeEnum.IPv4)metodo potrebbe essere un modo migliore per filtrare tali qualità piuttosto che ispezionare il tipo di calcestruzzo tramite instanceof. Cosa succede se si desidera dividere la classe di implementazione IPv4 in un secondo momento? Non che sia sempre meglio, ma è una considerazione.
Steven Schlansker,

@StevenSchlansker Potrebbe funzionare per quella specifica classe. E se fosse necessario ispezionare il tipo di calcestruzzo per vedere se è possibile un cast (o si dovrebbe semplicemente lanciare e catturare l'eccezione?) Inet6Address implementa più metodi di InetAddress. Sarebbe difficile lavorare con le interfacce (un enum che elenca ogni classe nel pacchetto? O caricatore di classi?) E ciò significherebbe che il metodo dovrebbe essere implementato a mano (o con qualche codice di riflessione in Object). Considera come fare (o instanceof Serializable) || (o instanceof Externalizable). instanceof è meglio dell'alternativa

1

È possibile utilizzare il metodo getClass ().

Sei sicuro di aver bisogno di tre classi diverse? Forse una classe con un interruttore interno servirà meglio?


7
getClasse instanceofcondividere i lati negativi. Il polimorfismo è migliore di entrambi quando si adatta, e non vedo che non si adatta al caso d'uso di OP.

Non ho nulla contro la tua prima frase. Ma il secondo - scusa, non riesco a capire cosa intendi.
Gangnus,

1
Con getClassnon condivido ancora lo stesso problema dell'utilizzo instanceof? Dovrò ancora scoprire quale ho e quindi chiamare un insieme di funzioni. Idealmente, voglio un metodo che restituisca i dati specifici di quella classe senza la necessità di eseguire il cast su quell'oggetto.
Thomas Mitchell,

Mi lamento di aver ignorato il polimorfismo, poiché spesso è una scelta migliore. Sono abbastanza sicuro che il caso d'uso nella domanda possa essere fatto con il polimorfismo, quindi non vedo nemmeno la necessità di usare. (A parte questo, riprodurre semplicemente la risposta di qualcun altro non è carino.)

2
@Gangus Non lo considero un "attacco", intendo senza offesa. Ma comunque. No, la domanda non è "cos'altro può essere usato", è "c'è un modo migliore per farlo". A meno che tu non voglia discutere, getClassè un modo migliore per farlo, non ha affari a prendere gran parte della risposta ;-)

1

In genere, quando mi ritrovo a voler conoscere il tipo di qualcosa, significa che ho implementato la struttura dell'oggetto in modo errato. La maggior parte di queste volte si tratta di violare LSP .

Ci sono volte, tuttavia, in cui vorrei avere un modo per eseguire l'invio dinamico e salvare una tonnellata di codice della piastra della caldaia e rendere la mia struttura a prova di futuro. C # fornisce la parola chiave dinamica nelle nuove versioni del framework ma, per quanto ne so, Java non ha ancora qualcosa di simile.

Detto questo, instanceof è generalmente meglio di confrontare le classi in quanto supporterà l'ereditarietà in modo corretto. Puoi anche usare metodi come isAssignableFrom e altri dall'API di riflessione. Se vuoi implementare qualcosa come l'invio dinamico, puoi farlo tramite l'API di riflessione ma attenzione, sarà lento. Usa con cautela, idealmente dovresti correggere la struttura degli oggetti e il desing della tua app se puoi.

Spero che sia di aiuto

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.