Stack Extending LinkedList. Una violazione del principio di sostituzione di Liskov?


13

Esiste una classe LinkedList con funzioni come add_first (), add_last (), add_after (), remove_first (), remove_last () e remove ()

Ora esiste una classe Stack che fornisce funzionalità come push (), pop (), peek () o top () e per implementare questi metodi estende i metodi della classe LinkedList. È una violazione del principio di sostituzione di Liskov?

Ad esempio, considerare il caso add_after () per aggiungere un nodo all'ennesima posizione di un Elenco collegato. Questo può essere fatto nella classe base ma non nella classe Stack. Le postcondizioni vengono indebolite qui o modifichi il metodo add_after () per aggiungere in cima allo Stack?

Inoltre, se non una violazione, questo cattivo design è? E come implementeresti la funzionalità Stack usando la classe LinkedList?


6
La domanda Quale sarebbe lo svantaggio di definire una classe come sottoclasse di un elenco di se stessa? chiede un problema leggermente diverso, ma la maggior parte delle risposte si applica anche qui: è meglio creare uno Stack con un Elenco come membro privato piuttosto che ereditare da Elenco.
amon,

7
Sì, questo è un cattivo design poiché ti impedirà di cambiare la rappresentazione interna dello stack in qualcosa di diverso da un elenco collegato (ad esempio un array). Stai anche esponendo operazioni che le pile di solito non supportano. Usa la composizione invece dell'eredità.
Lee,

2
Vuoi estendere LinkedList? Potresti voler dare ascolto al consiglio di un certo Joshua Bloch (che ha avuto un ruolo importante nella progettazione del framework delle raccolte Java) quando ha detto "Preferisci la composizione rispetto all'eredità" - Forse hai una LinkedListclasse interna alla tua pila, ma non la estendi?
corsiKa

1
Direi che non può soddisfare il principio di sostituzione di Liskov, perché "uno stack è una specie di elenco collegato" non è una vera affermazione. "Stack" è davvero un'interfaccia (intendo concettualmente, non il costrutto Java). Uno stack può essere implementato con un elenco collegato. Come altri hanno già detto, useresti un membro di dati privati ​​di tipo LinkedListche svolge il lavoro pesante dietro le quinte (composizione). In questo modo gli utenti del tuo codice non possono usare accidentalmente uno Stack dove avevano bisogno di un Elenco o viceversa.
Jasmijn,

1
Sembra che ciò che sarebbe più sano sarebbe il contrario. Se lo facessi, probabilmente una classe di elenco collegato implementerebbe un'interfaccia "stack" in quanto pienamente in grado di farlo. Altrimenti questo è il modo sbagliato in quanto uno stack è un concetto, un elenco collegato è un'implementazione che può fungere da stack tra le altre cose.
Valità,

Risposte:


31

Ora esiste una classe Stack che fornisce funzionalità come push (), pop (), peek () o top () e per implementare questi metodi estende i metodi della classe LinkedList. È una violazione del principio di sostituzione di Liskov?

No. Va benissimo aggiungere metodi in un sottotipo.

Ad esempio, considerare il caso add_after () per aggiungere un nodo all'ennesima posizione di un Elenco collegato. Questo può essere fatto nella classe base ma non nella classe Stack.

Questa è una violazione dell'LSP. L'LSP afferma che le istanze di un sottotipo devono essere sostituibili con le istanze di un supertipo senza modificare le proprietà desiderabili di un programma. Se un sottotipo rimuove un metodo, qualsiasi codice che lo chiama si arresterà in modo anomalo (o otterrà NoMethodErrorun'eccezione o qualcosa del genere). Chiaramente, "non andare in crash" è una proprietà desiderabile.

Le postcondizioni vengono indebolite qui o modifichi il metodo add_after () per aggiungere in cima allo Stack?

Modificare il add_after()metodo in questo modo è una violazione della Regola storica (la più importante delle regole!) E quindi non aiuta a correggere la violazione dell'LSP.

E come implementeresti la funzionalità Stack usando la classe LinkedList?

Usando la composizione.

NOTA: tutto ciò che ho scritto sopra si applica solo alle lingue che confondono il sottotipo e la sottoclasse! LSP riguarda il sottotipo , non la sottoclasse. In una lingua che non confonde le due cose, sarebbe perfettamente accettabile creare Stackuna sottoclasse di LinkedList, purché non la trasformi in un sottotipo di LinkedList.


9
Qual è la regola della storia? Non sono riuscito a trovarlo su Internet.
Zapadlo,

10
Quando si manipola un oggetto di un sottotipo e lo si osserva attraverso i metodi del supertipo, deve essere impossibile osservare una storia che non può essere osservata con un oggetto del supertipo. Questa regola è quella che rende l'LSP applicabile ai linguaggi non funzionali. Tutte le altre cose erano già note da molto tempo. Le regole pre e postcondizione sono riformulazioni delle regole di co-e contravarianza per i tipi di funzione. La regola della cronologia rende tutto ciò applicabile ai dati mutabili. Senza di essa, l'LSP sarebbe utile solo per linguaggi puramente funzionali.
Jörg W Mittag,

2
Penso che la spiegazione nell'articolo di Wikipedia sia ragionevolmente buona: wikipedia.org/wiki/Liskov_substitution_principle Ma come sempre, dovresti davvero leggere la fonte originale.
Jörg W Mittag,

@JörgWMittag: anche se ritengo ragionevole che i tipi includano nel loro contratto garanzie su quale "storia" sarà o non sarà osservata, non penso che dovrebbe essere necessario che ogni supertipo sia in grado di produrre ogni sequenza di osservazioni ciò potrebbe essere possibile su un oggetto del sottotipo - semplicemente che il supertipo documenta la possibilità che i consumatori del supertipo possano osservare tali sequenze.
Supercat,

1

Poiché tutto è già stato affrontato da Jörg W Mittag, ho appena elaborato un po 'la parte seguente:

Le postcondizioni vengono indebolite qui o modifichi il metodo add_after () per aggiungere in cima allo Stack?

Fondamentalmente, quando c'è una domanda se una gerarchia viola LSP, dipende dal contratto che poni. Quindi, quale contratto add_afterha? Se suona, per quanto folle, come "Aggiungi un nodo all'ennesima posizione o in alto", allora stai bene, la post-condizione è soddisfatta, LSP non è violato. Altrimenti è una violazione di LSP.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.