Direi che, correndo il rischio di essere abbattuto, quell'ereditarietà è un odore di codice in sé:)
Il problema con l'ereditarietà è che può essere utilizzato per due scopi ortogonali:
- interfaccia (per polimorfismo)
- implementazione (per il riutilizzo del codice)
Avere un unico meccanismo per ottenere entrambi è ciò che porta in primo luogo "l'abuso di ereditarietà", poiché la maggior parte delle persone si aspetta che l'ereditarietà riguardi l'interfaccia, ma potrebbe essere utilizzata per ottenere l'implementazione di default anche da programmatori altrimenti accurati (è solo così facile da trascurare questo ...)
In effetti, i linguaggi moderni come Haskell o Go hanno un'eredità abbandonata per separare entrambe le preoccupazioni.
Ritorno in pista:
Una violazione del Principio di Liskov è quindi il segnale più sicuro, poiché significa che la parte "interfaccia" del contratto non è rispettata.
Tuttavia, anche quando l'interfaccia è rispettata, potresti avere oggetti che ereditano da classi di base "grasse" solo perché uno dei metodi è stato ritenuto utile.
Quindi il Principio di Liskov di per sé non è abbastanza, quello che devi sapere è se il polimorfismo è usato . Se non lo è, allora non c'era molto da fare ereditando in primo luogo, è un abuso.
Sommario:
- applica il
Liskov Principle
- verifica che sia effettivamente utilizzato
Un modo per aggirarlo:
Imporre una netta separazione delle preoccupazioni:
- ereditano solo dalle interfacce
- usa la composizione per delegare l'implementazione
significa che almeno un paio di sequenze di tasti sono necessarie per ogni metodo, e improvvisamente le persone cominciano a pensare se sia una così grande idea riutilizzare questa classe "grassa" solo per una piccola porzione di esso.