Domanda sui membri nelle classi derivate (nuova vs override)

0

Sto lavorando al libro Head First Design Patterns e sono attualmente nel capitolo Decorator Pattern. Dal momento che gli esempi di libri sono scritti in Java, sto adattando il, a C # come vado.

Questo esempio simula un sistema di ordinazione di coffee shop. Esiste una classe base astratta per Beverage e sottoclassi per bevande specifiche (es: Espresso ). Le classi di decoratore sono usate per aggiungere condimenti e modifiche alle bevande. Esiste una classe astratta CondimentDecorator che deriva da Beverage e quindi sottoclassi come Mocha per i singoli decoratori. Sintesi con tutti i file: link

La mia domanda - nella classe base Beverage , la stringa descrittiva è impostata su "Bevanda sconosciuta". Il costruttore di una bevanda specifica lo imposta sul nome della bevanda, quindi se uso:

Beverage espresso = new Espresso();
Console.WriteLine($"{espresso.GetDescription()}");

Risponde a "Espresso". Ora, quando si usa il decoratore, il metodo GetDescription viene sovrascritto, nella classe Mocha aggiunge "Mocha" dopo la descrizione della bevanda.

public override string GetDescription()
{
    return beverage.GetDescription() + " Mocha";
}

Se utilizzo il modificatore override in CondimentDecorator.cs:

public abstract override string GetDescription();

Funziona come previsto. Corro:

Beverage espresso = new Espresso();
Console.WriteLine($"{espresso.GetDescription()}"); // Espresso
espresso = new Mocha(espresso);
Console.WriteLine($"{espresso.GetDescription()}"); // Espresso Mocha

Tuttavia, se cambio il modificatore in new in CondimentDecorator.cs in questo modo:

public abstract new string GetDescription();

E esegui lo stesso codice, ottengo i seguenti risultati:

Beverage espresso = new Espresso();
Console.WriteLine($"{espresso.GetDescription()}"); // Espresso
espresso = new Mocha(espresso);
Console.WriteLine($"{espresso.GetDescription()}"); // Unknown beverage

Sono un po 'confuso perché questo accade ... dal momento che GetDescription viene chiamato in Mocha come questo ...

public override string GetDescription()
{
    return beverage.GetDescription() + " Mocha";
}

... e la bevanda è un riferimento all'oggetto espresso originale, perché il codice non riprende la descrizione che è stata impostata quando è stata creata un'istanza di Espresso ? Per come ho capito, new nasconderebbe il metodo originale GetDescription nella classe base mentre override estenderebbe quel metodo. Non sono sicuro del motivo per cui ciò influisce sulla descrizione che il programma legge - la "bevanda sconosciuta" di Mocha , che ottiene quel valore dalla classe Beverage da cui deriva, o "Espresso" dell'oggetto bevanda I creato con la descrizione impostata nel costruttore.

Sono certo che sto solo fraintendendo qualcosa di basilare sull'ereditarietà e su come funzionano le parole chiave nuove e sovrascrivibili, se qualcuno può gettare un po 'di luce su questo lo apprezzerei!

Grazie!

    
posta Jim 30.10.2016 - 04:13
fonte

2 risposte

1

La cosa confusa su new è che crea un secondo metodo con lo stesso nome di un metodo esistente.

Parliamo di questa riga di codice:

public abstract new string GetDescription();

Grazie a questo codice, CondimentDecorator ora ha due % metodiGetDescription: ha

  • GetDescription , ereditato da Beverage , e anche
  • GetDescription , appena dichiarato in CondimentDecorator .

Ora, ogni volta che chiami GetDescription , il compilatore deve decidere quale metodo GetDescription da chiamare. Lo fa osservando il tipo dichiarato della variabile su cui stai chiamando il metodo (non il tipo di runtime). Se il tipo dichiarato è Beverage , chiama il metodo che è ereditato da Beverage ; se il tipo dichiarato è CondimentDecorator , chiama il metodo che è stato appena dichiarato in CondimentDecorator .

Diamo un'occhiata al tuo codice chiamante ora:

Beverage espresso = new Espresso();
Console.WriteLine($"{espresso.GetDescription()}"); // Espresso
espresso = new Mocha(espresso);
Console.WriteLine($"{espresso.GetDescription()}"); // Unknown beverage

Quello che sta succedendo è che dal momento che il tipo dichiarato della variabile espresso è Beverage , il compilatore lo interpreta sempre come una chiamata al metodo GetDescription che è ereditato da Beverage . Il fatto che il tipo runtime di espresso sia Mocha non ha importanza.

    
risposta data 02.11.2016 - 17:43
fonte
1

Penso che questo articolo lo spieghi:

link

Fondamentalmente dipende dal fatto che la tua bevanda sia acceduta come una Moka o Expresso e quale sia in realtà.

Supponiamo di avere un caso semplice in cui

Mocha: Espresso

poi

((Espresso) moka) .GetDescription () == "espresso" se si "nuovo" anziché "sovrascrivere"

quindi se vuoi fare

foreach(Beverage b in List) 
{
    //print description
}

quindi dovresti eseguire l'override

Ora il tuo esempio particolare è complicato dal tuo decoratore. che eredita anche dalla bevanda.

hai

Espresso: bevanda

e

Mocha: Decorator: Beverage

quindi quando usi "nuovo" su Mocha, ma chiama

((bevande) moka) .GetDescription ()

ottieni il risultato Beverage "bevanda sconosciuta"

    
risposta data 30.10.2016 - 11:59
fonte

Leggi altre domande sui tag