Una classe dovrebbe conoscere le sue sottoclassi?

22

Una classe dovrebbe conoscere le sue sottoclassi? Per esempio, una classe dovrebbe fare qualcosa di specifico per una determinata sottoclasse?

Il mio istinto mi dice che è un cattivo design, sembra un anti-pattern di qualche tipo.

    
posta m4design 26.11.2013 - 13:43
fonte

5 risposte

31

La risposta implicita dal concetto di classi è "no".

Qualsiasi azione, dato o relazione che stai gestendo fa parte di tutte le sottoclassi, quindi dovrebbe essere gestita nella superclasse senza verificare il tipo effettivo. Oppure si applica solo ad alcune sottoclassi - quindi dovresti eseguire controlli di tipo run-time per fare la cosa giusta, la superclasse dovrebbe essere cambiata ogni volta che qualcun altro ne eredita (o potrebbe fare silenziosamente la cosa sbagliata), le modifiche nelle classi derivate possono rompere la superclasse invariata, ecc.

In breve, si ottengono un numero di conseguenze negative che di solito sono abbastanza gravi da respingere tali soluzioni in modo inavvertito. Se molte delle sottoclassi fanno la stessa cosa e vuoi evitare la duplicazione del codice (praticamente sempre una buona cosa), una soluzione migliore è introdurre una classe di livello medio da cui tutte quelle sottoclassi possono ereditare il codice.

    
risposta data 26.11.2013 - 13:56
fonte
16

Non solo dovrebbe non sapere, semplicemente non ! Di solito, una classe può essere estesa sempre e ovunque. Può essere esteso da classi che non hanno nemmeno esistere quando è stato scritto.

Alcune lingue consentono di estendere le classi per essere controllate dalla superclasse. In Scala, una classe può essere contrassegnata come sealed , il che significa che può essere estesa solo da altre classi all'interno della stessa unità di compilazione (file sorgente). Tuttavia, a meno che quelle sottoclassi non siano anche sealed o final , le sottoclassi possono essere ulteriormente estese da altre classi.

In Scala, questo è usato per modellare i tipi di dati algebrici chiusi, quindi il tipo haskell List canonico:

data List a = Nil | Cons a (List a)

può essere modellato in Scala in questo modo:

sealed trait List[+A]

case object Nil extends List[Nothing]

final case class Cons[+A] extends List[A]

E puoi garantire che solo queste due "classi" esistono perché List è sealed e quindi non può essere esteso al di fuori del file, Cons è final e quindi non può essere esteso affatto e Nil è un object che non può essere comunque esteso.

Ma questo è un caso d'uso specifico (modellando i tipi di dati algebrici tramite l'ereditarietà) e anche in questo caso, la superclasse in realtà non conosce le sue sottoclassi. È più una garanzia per l'utente del tipo List che se fa una discriminazione caso di Nil e Cons , non ci sarà nessun altro un'alternativa spuntando alle sue spalle.

    
risposta data 26.11.2013 - 14:17
fonte
4

La risposta semplice è No.

Rende il codice fragile e svuota due principi di base della programmazione orientata agli oggetti.

  • Principio di sostituzione di Liskov
  • Apri il principio Chiudi
risposta data 27.11.2013 - 17:54
fonte
1

Sì, a volte. Ad esempio, quando esiste un numero limitato di sottoclassi esistono. Un modello di visitatore è un'illustrazione dell'utilità di questo approccio.

Esempio: i nodi AST (Abstract Syntax Tree) di alcune grammatiche ben definite possono essere tutti ereditati da una singola classe Node che implementa un pattern visitor per gestire tutti i tipi di nodi.

    
risposta data 26.11.2013 - 15:18
fonte
1

Se scrivo un componente per un'azienda e successivamente, dopo che me ne sono andato, qualcuno lo estende per i propri scopi, dovrei esserne informato?

No!

Uguale alle classi. Fidati del tuo istinto.

    
risposta data 26.11.2013 - 16:10
fonte