"Super" vs "metodo protetto" per l'esecuzione di codice comune

6

In molte lingue, super() ti consente di chiamare il metodo genitore che hai sovrascritto. Ho utilizzato super nel mio Javascript (con un'implementazione orientata agli oggetti) per eseguire codice comune per un lungo periodo senza problemi. Ora ho finalmente colpito un caso in cui chiamare un metodo di classe base protected sarebbe stato meglio che chiamare super .

Ecco un esempio concreto.

Grandparent -> Parent -> Kid

Avevo bisogno di aggiungere un Kid. È identico a Parent tranne per un metodo chiamato someMethod. Kid's someMethod aveva bisogno di fare le cose comuni di Nonno, ma non delle cose specifiche di Parent. So SomeMethod di Kid non poteva chiamare super perché ciò avrebbe attivato il codice specifico di Parent. Invece di cambiare la mia grande struttura di classe, ho appena creato Kid duplicato il codice comune di Nonno.

Grandparent {
 someMethod {
  do common stuff
 };
}

Parent: Grandparent {
 someMethod {
  super();
  do parent specific stuff
 }
}

Kid: Parent {
 someMethod {
  duplicate of common stuff
  do kid specific stuff 
 }
}

Nel mio libro, il codice duplicato è sbagliato. Se solo il nonno scrivesse le sue cose comuni come metodo protetto, non avrei bisogno di duplicare il codice.

Grandparent {
 protected commonMethod
 virtual someMethod
}

Parent: Grandparent {
 someMethod {
  commonMethod
  do parent specific stuff
 }
}

Kid: Parent {
 someMethod {
  commonMethod
  do kid specific stuff
 }
} 

Devo semplicemente smettere di usare super e passare ai metodi protected per l'esecuzione di codice comune? Ci sono dei problemi con i metodi protetti per l'esecuzione di materiale comune?

    
posta JoJo 18.05.2011 - 00:00
fonte

1 risposta

15

No, non dovresti smettere di usare super , dovresti interrompere l'implementazione di progetti OO non validi.

Nonostante il fatto che non stiamo parlando di vera eredità, perché stai eredita dalla parent se non si desidera che la sua funzionalità? Stai rompendo l'astrazione. La classe a livello di foglia non dovrebbe sapere nulla sull'attuale implementazione di parent , certamente non abbastanza per sapere che non vuole che vengano eseguite le "cose specifiche dei genitori".

Più in generale, dovresti onorare il Principio di sostituzione di Liskov quando possibile e solo creando tipi derivati che possono essere effettivamente sostituiti all'ingrosso per i tipi di base. Questo sembra essere stato violato qui; il parent ha modificato il contratto del grandparent in modo che altre generazioni di discendenti debbano disabilitarlo per funzionare correttamente.

Per quanto ne so, il tuo kid dovrebbe essere un discendente di grandparent .

Separatamente:

  • Esistono altri modi per evitare la duplicazione. Non tutto deve essere basato sull'eredità; la composizione e il semplice riferimento vecchio stanno benissimo. Assicurati di non violare il SRP .

  • Almeno nella maggior parte delle implementazioni OO, protected e virtual non si escludono a vicenda. Un metodo di sostituzione è ancora libero di chiamare i metodi della sua base protetti, quindi se si prevede la necessità di classi derivate di utilizzare funzionalità specifiche della base, poi astratta in un metodo protetto. Ciò non ha assolutamente alcuna influenza sul fatto che un altro metodo debba essere virtuale.

Penso che la radice del problema risieda proprio in questa frase:

I've been using super in my Javascript... to run common code

L'ereditarietà non è principalmente uno strumento per il riutilizzo del codice. È uno strumento per ... beh, eredità , cioè quando è necessario essere in grado di sostituire un'implementazione con un'altra senza perdita di fedeltà (polimorfismo) o quando la classe base non avrà tutte le informazioni ha bisogno di eseguire una particolare operazione e deve essere in grado di delegare questo a una classe derivata (astrazione).

Se si utilizza l'ereditarietà per il solo scopo di inceppamenti nel codice che viene utilizzato di frequente, allora hai completamente frainteso il concetto; usa la composizione per quello, o l'inferno, scrivi solo un mucchio di funzioni. Non c'è alcun motivo per cercare di eredità falso quando il migliore risultato possibile è ancora inferiore alle alternative più semplici.

    
risposta data 18.05.2011 - 00:32
fonte

Leggi altre domande sui tag