Quando utilizzare la variabile di interfaccia = nuova variabile di classe OOP

0

Ho visto spesso persone che usano questo codice come

interface IAnimal 
{
    void die();
}

class Cat : IAnimal 
{
    void die() { ... }
    void meow() { ... }
}

IAnimal anAnimal = new Cat();
Cat aCat= new Cat();

C # sa per certo che anAnimal.die() funziona, perché die() è definito in IAnimal . Ma non ti lascerà fare anAnimal.meow() anche se è un Cat , mentre aCat può richiamare entrambi i metodi.

Perché e quando dovremmo scrivere questo tipo di codice:

IAnimal anAnimal = new Cat();

Qual è il vantaggio?

    
posta Thomas 20.02.2014 - 10:05
fonte

3 risposte

6

Perché anche se il compilatore potrebbe dedurre che la chiamata di meow() riuscirebbe in questo caso, non può farlo in ogni programma concepibile, ed è molto meglio avere un semplice, facile- per ricordare la politica di "nessuna inferenza di tipo" rispetto a "Ho intenzione di provare qualche inferenza di tipo per te, ma ti avverto, non troverò tutte le chiamate legali che potresti aspettarti, quindi nessuna garanzia ".

Pertanto, se chiamerai meow() in ogni caso, non è assolutamente necessario dichiarare qualcosa come Animal . Basta andare avanti e ammettere che è un Cat . Le interfacce sono un costrutto utile, ma possono guadagnare la loro paga solo se sei disposto a lasciare che facciano la loro cosa di astrazione, e dimenticare le specie esatte.

In generale, raramente ha senso dichiarare qualcosa come un supertipo astratto quando poi lo assegni immediatamente a una chiamata del costruttore, cioè un tipo concreto. Ma immagina di avere un DogFactory , un CatFactory e un BirdFactory , ognuno dei quali implementa un'interfaccia comune PetFactory . Il PetFactory conterrebbe un metodo Animal getPet() , e ogni fabbrica di cemento farebbe qualcosa come return new Cat() . Il tipo concreto è necessario per costruire effettivamente un oggetto; l'interfaccia è necessaria in modo che i vari provider possano soddisfare tutti la stessa interfaccia, il che semplifica l'intreccio dell'applicazione a un livello superiore.

    
risposta data 20.02.2014 - 10:10
fonte
2
IAnimal anAnimal = new Cat();

Hai ragione. Questo non ha davvero un caso d'uso, poiché non ha alcun vantaggio diretto. Dato che stai codificando il tipo dell'oggetto ( Cat ), non viene ottenuto nulla dal downcasting del tipo di variabile che fa riferimento all'oggetto.

Tuttavia, il tuo argomento non è vero quando Cat non è codificato a macchina:

IAnimal anAnimal = myAnimalFinder.FindByName("Fido");

Non sai che animale hai intenzione di riavere.

Supponendo che il tuo software sia venduto ai veterinari, il risultato (basato sullo stesso nome) potrebbe essere diverso dal veterinario al veterinario. Il veterinario A ha curato un cane di nome Fido, il veterinario B ha trattato un gatto di nome Fido.

Questo è il caso di utilizzo reale , che in realtà ha senso nel contesto. La versione semplificata a cui ti riferivi inizialmente si trova più comunemente in esempi , non in codice live.

But it won't let you do anAnimal.meow() even though it's a Cat

Osservando il caso d'uso reale, diventa chiaro il motivo per cui non puoi chiamare meow() . Non hai modo di garantire che in realtà stai recuperando un Cat , quindi non c'è modo di sapere se l'animale restituito può miagolare o no.

    
risposta data 15.05.2018 - 10:37
fonte
0

Le interfacce generalmente definiscono i comportamenti e le classi che implementano tali interfacce sono garantite per mostrare tali comportamenti.

interface IDriveable
{
   drive(); 
}

class BMW : IDriveable
{
   drive(); 
   setAirConditioning( int temperature ); 
}

class ModelT : IDriveable
{
   drive(); 
}

Entrambe le auto possono essere guidate.

La nuova e brillante BMW può anche fare la cosa con aria condizionata, ma questa è non una caratteristica dell'essere guidabile.

    
risposta data 15.05.2018 - 12:46
fonte

Leggi altre domande sui tag