Domanda

Ho a che fare con una base di codice di grandi dimensioni che ha molte classi e molti metodi astratti su queste classi. Sono interessato alle opinioni delle persone su cosa dovrei fare nella seguente situazione.

Se ho una classe Parent-A con un metodo astratto. Ci saranno solo 2 bambini. Se Child-B implementa AbstractMethodA ma Child-B non funziona come non si applica.

Dovrei

  1. Rimuovere la parola chiave astratta dal genitore e utilizzare virtuale o dinamico?
  2. Fornisce un'implementazione vuota del metodo.
  3. Fornire un'implementazione che genera un errore se chiamato.
  4. Ignora l'avviso.

Modifica: grazie per tutte le risposte. Confermò il mio sospetto che ciò non dovesse accadere. Dopo ulteriori indagini risulta che i metodi non sono stati affatto utilizzati, quindi li ho rimossi del tutto.

È stato utile?

Soluzione

Se AbstractMethodA non si applica a Child-B, Child-B non dovrebbe ereditare da Parent-A.

O per prendere il contrapositivo, se Child-B eredita da Parent-A e AbstractMethodA non si applica al figlio, allora non dovrebbe essere nemmeno nel genitore.

Inserendo un metodo in Parent-A, stai dicendo che il metodo si applica a Parent-A e a tutti i suoi figli. Ecco cosa significa eredità , e se la usi per significare qualcosa di diverso, finirai per una seria disputa con il tuo compilatore.

[Modifica - detto questo, la risposta di Mladen Prajdic va bene se il metodo si applica, ma non dovrebbe fare nulla per una o più delle classi coinvolte. Un metodo che non fa nulla è che IMO non è la stessa cosa di un metodo che non è applicabile, ma forse non intendiamo la stessa cosa per "non si applica" &

Un'altra tecnica è implementare comunque il metodo in Child-B, ma farlo fare qualcosa di drastico come restituire sempre un fallimento, o lanciare un'eccezione o qualcosa del genere. Funziona, ma dovrebbe essere considerato un po 'bizzarro piuttosto che un design pulito, poiché significa che i chiamanti devono sapere che la cosa che hanno che stanno trattando come Parent-A è davvero un bambino-B e quindi non dovrebbero chiamare AbstractMethodA. Fondamentalmente hai scartato il polimorfismo, che è il principale vantaggio dell'eredità OO. Personalmente preferisco farlo in questo modo piuttosto che avere un'implementazione che genera eccezioni nella classe base, perché quindi una classe figlio non può "accidentalmente" comportarsi male da "dimenticare" " per implementare il metodo a tutti. Deve implementarlo e se lo implementa per non funzionare, lo fa esplicitamente. Una brutta situazione dovrebbe essere rumorosa.

Altri suggerimenti

Se l'implementazione nei discendenti non è obbligatoria, dovresti scegliere 1 + 2 (ovvero metodo virtuale vuoto nell'antenato)

Penso che, in generale, non dovresti ereditare dalla classe astratta se non sei in grado di implementare tutti i metodi astratti in primo luogo, ma capisco che ci sono alcune situazioni in cui ha ancora senso farlo , (vedi la classe Stream e le sue implementazioni).

Penso che dovresti semplicemente creare implementazioni di questi metodi astratti che generano NotImplementedException.

Puoi anche provare a usare ObsoleteAttribute in modo tale che chiamare quel particolare metodo sia un errore di compilazione (oltre a lanciare NotImplementedException ovviamente). Nota che ObsoleteAttribute non è proprio pensato per essere usato per questo, ma immagino che se usi un messaggio di errore significativo con commenti, va bene.

Esempio di codice obbligatorio:

[Obsolete("This class does not implement this method", true)]
public override string MyReallyImportantMethod()
{
    throw new NotImplementedException("This class does not implement this method.");
}

rendilo virtuale vuoto nella classe base e sovrascriverlo nei bambini.

Potresti usare le interfacce. Quindi Child-A e Child-B possono entrambi implementare metodi diversi e comunque ereditare da Parent-A. Le interfacce funzionano come metodi astratti in quanto costringono la classe a implementarle.

Se alcune sottoclassi (B1, B2, ...) di A sono utilizzate per un sottoinsieme dei suoi metodi rispetto ad altri (C1, C2, ...), si potrebbe dire che A può essere suddiviso in B e C .

Non conosco troppo bene Delphi (per niente :)), ma pensavo che proprio come ad es. in Java e COM, una classe può "implementare" più interfacce. In C ++ questo può essere ottenuto solo moltiplicando le classi astratte.

Più concreto: vorrei creare due classi astratte (con metodi astratti) e cambiare l'albero ereditario.

Se ciò non fosse possibile, una soluzione alternativa potrebbe essere un "Adattatore": una classe intermedia A_nonB_ con tutti i metodi B implementati vuoti (e che genera un avviso su come chiamarli) e A_nonC_. Quindi modifica l'albero delle eredità per risolvere il tuo problema: B1, B2, ... eredita da A_nonC_ e C1, C2, ... eredita da A_NonB_.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top