Stack memperpanjang LinkedList. Pelanggaran Prinsip Pergantian Liskov?

13

Kelas LinkedList ada dengan fungsi-fungsi seperti add_first (), add_last (), add_after (), remove_first (), remove_last (), dan remove ()

Sekarang ada kelas Stack yang menyediakan fungsionalitas seperti push (), pop (), peek () atau top (), dan untuk mengimplementasikan metode ini ia memperluas metode kelas LinkedList. Apakah ini merupakan pelanggaran terhadap Prinsip Pergantian Liskov?

Sebagai contoh, pertimbangkan case add_after () untuk menambahkan node di posisi ke-n dari Daftar Tertaut. Ini bisa dilakukan di kelas dasar tetapi tidak di kelas Stack. Apakah postconditions dilemahkan di sini atau Anda memodifikasi metode add_after () untuk ditambahkan ke bagian atas Stack?

Juga, jika bukan pelanggaran, apakah desain yang buruk ini? Dan bagaimana Anda mengimplementasikan fungsionalitas Stack menggunakan kelas LinkedList?

jxvmiranda
sumber
6
Pertanyaannya: Apa kerugiannya mendefinisikan kelas sebagai subkelas dari daftar itu sendiri? bertanya tentang masalah yang sedikit berbeda, tetapi sebagian besar jawaban berlaku di sini juga: Anda lebih baik membuat Stack dengan Daftar sebagai anggota pribadi daripada mewarisi dari Daftar.
amon
7
Ya ini adalah desain yang buruk karena itu akan mencegah Anda mengubah representasi internal stack menjadi sesuatu selain daftar yang ditautkan (misalnya array). Anda juga mengekspos operasi yang tumpukan biasanya tidak mendukung. Gunakan komposisi alih-alih warisan.
Lee
2
Apakah Anda ingin memperpanjang LinkedList? Anda mungkin ingin memperhatikan saran dari Joshua Bloch tertentu (yang memainkan peran utama dalam merancang kerangka koleksi Java) ketika dia berkata "Lebih suka komposisi daripada warisan" - Mungkin memiliki bagian LinkedListdalam kelas stack Anda, tetapi tidak benar-benar memperpanjangnya?
corsiKa
1
Saya akan mengatakan itu tidak dapat memenuhi prinsip substitusi Liskov, karena "tumpukan adalah semacam daftar yang ditautkan" bukan pernyataan yang benar. "Stack" benar-benar sebuah antarmuka (maksud saya secara konseptual, bukan konstruksi Java). Tumpukan dapat diimplementasikan dengan daftar tertaut. Seperti orang lain katakan, Anda akan menggunakan anggota data pribadi tipe LinkedListyang melakukan mengangkat berat di belakang layar (komposisi). Dengan begitu pengguna kode Anda tidak dapat secara tidak sengaja menggunakan Stack di mana mereka membutuhkan Daftar atau sebaliknya.
Jasmijn
1
Tampaknya apa yang akan lebih waras akan menjadi kebalikannya. Jika saya melakukan ini, saya mungkin akan memiliki kelas daftar tertaut menerapkan antarmuka "tumpukan" karena sepenuhnya mampu melakukannya. Kalau tidak, ini adalah jalan yang salah karena stack adalah sebuah konsep, daftar tertaut adalah implementasi yang dapat bertindak sebagai stack di antara hal-hal lain.
Vality

Jawaban:

31

Sekarang ada kelas Stack yang menyediakan fungsionalitas seperti push (), pop (), peek () atau top (), dan untuk mengimplementasikan metode ini ia memperluas metode kelas LinkedList. Apakah ini merupakan pelanggaran terhadap Prinsip Pergantian Liskov?

Tidak apa-apa menambahkan metode dalam subtipe.

Sebagai contoh, pertimbangkan case add_after () untuk menambahkan node di posisi ke-n dari Daftar Tertaut. Ini bisa dilakukan di kelas dasar tetapi tidak di kelas Stack.

Ini merupakan pelanggaran terhadap LSP. LSP mengatakan bahwa instance subtipe harus dapat diganti untuk instance supertype tanpa mengubah sifat yang diinginkan dari suatu program. Jika subtipe menghapus metode, maka kode apa pun yang memanggil metode itu akan macet (atau mendapatkan NoMethodErrorpengecualian, atau sesuatu di sepanjang baris itu). Jelas, "tidak menabrak" adalah properti yang diinginkan.

Apakah postconditions dilemahkan di sini atau Anda memodifikasi metode add_after () untuk ditambahkan ke bagian atas Stack?

Memodifikasi add_after()metode dengan cara ini adalah pelanggaran terhadap History Rule (yang paling penting dari aturan!) Dan dengan demikian tidak membantu memperbaiki pelanggaran terhadap LSP.

Dan bagaimana Anda mengimplementasikan fungsionalitas Stack menggunakan kelas LinkedList?

Dengan menggunakan komposisi.

CATATAN: Semua yang saya tulis di atas hanya berlaku untuk bahasa yang membingungkan subtyping dan subclassing! LSP adalah tentang subtyping , bukan subclassing. Dalam bahasa yang tidak bingung dua, akan diterima untuk membuat Stacksubclass dari LinkedList, selama Anda tidak membuatnya menjadi subtipe dari LinkedList.

Jörg W Mittag
sumber
9
Apa Aturan Sejarah? Saya gagal menemukannya di internet.
Zapadlo
10
Ketika memanipulasi objek subtipe, dan mengobservasinya melalui metode supertipe, pastilah mustahil untuk mengamati sejarah yang tidak bisa juga diamati dengan objek supertipe. Aturan ini adalah yang membuat LSP berlaku untuk bahasa yang tidak berfungsi. Semua hal lainnya sudah diketahui jauh sebelum itu. Aturan pra dan pascakondisi adalah reformulasi aturan co dan contravariance untuk tipe fungsi. Aturan sejarah membuat semua ini berlaku untuk data yang dapat diubah. Tanpa itu, LSP hanya akan berguna untuk bahasa yang murni fungsional.
Jörg W Mittag
2
Saya pikir penjelasan dalam artikel Wikipedia cukup bagus: wikipedia.org/wiki/Liskov_substitution_principle Tapi seperti biasa, Anda harus benar-benar membaca sumber aslinya.
Jörg W Mittag
@ JörgWMittag: Sementara saya akan berpikir masuk akal untuk jenis untuk dimasukkan dalam jaminan kontrak mereka tentang "sejarah" apa yang akan atau tidak akan diamati, saya tidak berpikir bahwa setiap supertipe harus mampu menghasilkan setiap urutan pengamatan yang mungkin terjadi pada objek subtipe - hanya bahwa supertipe mendokumentasikan kemungkinan bahwa konsumen supertipe dapat mengamati urutan tersebut.
supercat
1

Karena semuanya sudah ditangani oleh Jörg W Mittag, saya hanya menjelaskan sedikit pada bagian berikut:

Apakah postconditions dilemahkan di sini atau Anda memodifikasi metode add_after () untuk ditambahkan ke bagian atas Stack?

Pada dasarnya, ketika ada pertanyaan apakah beberapa hierarki melanggar LSP, itu tergantung pada kontrak apa yang Anda ajukan. Jadi, kontrak apa yang add_afterdimiliki? Jika kedengarannya gila, betapapun gila, seperti "Tambahkan simpul di posisi ke-n atau di atas", daripada Anda baik-baik saja, kondisi pasca terpenuhi, LSP tidak dilanggar. Kalau tidak, ini merupakan pelanggaran LSP.

Zapadlo
sumber