Perché utilizziamo parole chiave virtuali e override in c #

4

Qualcuno può spiegarmi quale sia il motivo di sovrascrivere le implementazioni della classe base (se non è astratto), perché non è una mossa etica modificare le caratteristiche della classe genitore secondo i desideri delle classi derivate. Il modo migliore è rendere astratte le classi di base e portare avanti la catena ereditaria. Mentre inizialmente progettiamo una gerarchia di classi raccogliamo o ricaviamo tutti i requisiti / caratteristiche essenziali che dovrebbero appartenere a una classe base. Pertanto, nel bel mezzo di un progetto non è necessario modificare le implementazioni della classe base. Secondo le mie conoscenze, l'implementazione della classe base dovrebbe essere una costante. Quindi, sotto questo aspetto, non c'è un vero uso della parola chiave "override" in c #. Se non è così, per favore spiegami un esempio.

    
posta Wageesha 17.09.2013 - 21:39
fonte

5 risposte

12

Molte volte avrai dipendenze nelle sottoclassi o potresti dover implementare le cose in modo diverso.

class BasicCarModel
{
    public virtual void Accelerate(double speed)
    {
         RotateFrontWheels(speed);
    }
}

class LuxuryCarModel : BasicCarModel
{
    public override void Accelerate(double speed)
    {
        RotateAllWheels(speed);
    }
}

Non c'è niente di sbagliato nel creare metodi virtual nelle classi concrete e in alcuni casi sono molto utili. La difficoltà è che molti programmatori alle prime armi violano il Principio di sostituzione di Liskov quando lo fanno. Ricorda che un metodo sottoposto a override dovrebbe sembrare fare la stessa cosa se usato come metodo base. Non dovrebbe rafforzare o indebolire le precondizioni del metodo di base.

Nell'esempio che ho dato, la differenza tra la classe base e la classe derivata era nella meccanica di come l'auto ha accelerato, non nei valori consentiti per speed . Non ha lanciato eccezioni che non erano previste da una classe chiamante.

Questo è un esempio forzato, ma il principio è lo stesso. Fai usa virtual e override quando necessario. Non violare l'LSP.

    
risposta data 19.09.2013 - 03:23
fonte
4

Ecco una classe non astratta che esegue alcune elaborazioni e una sottocategoria che esegue solo l'elaborazione in determinate ore del giorno.

class Foo
{
    public virtual bool IsReadyToProcess()
    {
        return true;
    }
    public void Process()
    {
        if (!IsReadyToProcess()) throw new Exception("Not ready");
        else
          // Process
    }
}

class TimeboundFoo : Foo
{
    public TimeboundFoo(int hour) { Hour = hour; }

    public int Hour { get; private set; }

    public override bool IsReadyToProcess()
    {
       return DateTime.Now.Hour == Hour;
    }
}

Utilizzo:

List<Foo> foos = new List<Foo>();
foos.Add(new Foo());
foos.Add(new TimeboundFoo(12));

foreach (var foo in foos)
{
   if (foo.IsReadyToProcess()) foo.Process();
}

A mezzogiorno, elaborerà entrambi gli oggetti Foo , ma in qualsiasi altra ora elaborerà solo quella. È un esempio molto elaborato, ma puoi generalizzare da qui.

    
risposta data 17.09.2013 - 21:50
fonte
1

I metodi virtuali / astratti e l'override sono comunemente usati in modello .

Il pattern template fornisce un modo per definire ciò che ritieni sia una buona guida generale per una classe da seguire, ma permetti ai futuri implementatori di essere più specifici, o addirittura unici nel loro modo di fare qualcosa.

    
risposta data 18.09.2013 - 00:20
fonte
1

Che ne dici di un caso semplice in cui DEVI utilizzare l'override:

Qualsiasi classe che implementa l'interfaccia IDisposable. (E qualsiasi classe che possiede una risorsa che deve essere ripulita dovrebbe implementarla.)

    
risposta data 20.09.2013 - 05:24
fonte
0

Nota: l'OP menziona che ti sembra opportuno ignorare le implementazioni di base delle classi astratte, quindi questa risposta è adattata a tale assunto.

Probabilmente è una cattiva idea ereditare da classi che non sono state progettate per l'ereditarietà (vedi perché i tipi concreti raramente sono utili come basi per ulteriori derivazione ). Molti esperti di C # ritengono che le classi C # dovrebbero essere sigillate per impostazione predefinita.

Vedi anche Perché sono così tante delle classi quadro sigillate? .

Tutto ciò detto, l'unica differenza tra una classe astratta e una classe concreta progettata per l'ereditarietà è che quest'ultima può essere istanziata. In alternativa, una classe concreta è come una classe astratta che non ha metodi privi di qualche forma di implementazione predefinita. Tutte le considerazioni sulla progettazione che consentono di ereditare da una classe astratta consentono anche di ereditare da una classe concreta progettata per l'ereditarietà.

Un esempio interessante è UserControl . Essere in grado di derivare da UserControl è di alto valore, dal momento che c'è molta funzionalità di asp.net che sfrutta il polimorfismo.

    
risposta data 19.09.2013 - 19:46
fonte

Leggi altre domande sui tag