LinkedList genişletme yığını. Liskov İkame İlkesinin ihlali mi?


13

Add_first (), add_last (), add_after (), remove_first (), remove_last () ve remove () gibi işlevlerle bir sınıf LinkedList var.

Şimdi push (), pop (), peek () veya top () gibi işlevler sağlayan bir Sınıf Stack var ve bu yöntemleri uygulamak için LinkedList sınıf yöntemlerini genişletiyor. Bu Liskov İkame İlkesinin ihlali midir?

Örneğin, Bağlantılı Listenin n'inci konumuna düğüm eklemek için add_after () örneğini düşünün. Bu temel sınıfta yapılabilir, ancak Stack sınıfında yapılamaz. Burada son koşullar zayıflıyor mu yoksa yığının en üstüne eklemek için add_after () yöntemini değiştiriyor musunuz?

Ayrıca, bir ihlal değilse, bu kötü tasarım mı? LinkedList sınıfını kullanarak Stack işlevini nasıl uygularsınız?


6
Sorusu başlı başına bir listesinin bir alt sınıf olarak bir sınıf tanımlamaya dezavantaj ne olurdu? biraz farklı bir sorun hakkında soru sorar, ancak yanıtların çoğu burada da geçerlidir: Listeden devralmak yerine bir Listeye sahip bir yığını özel üye olarak oluşturmak daha iyidir.
amon

7
Evet, bu kötü bir tasarımdır, çünkü yığının iç temsilini bağlantılı bir listeden (örneğin bir dizi) başka bir şeye değiştirmenizi önler. Ayrıca, yığınların genellikle desteklemediği işlemleri de ortaya koyarsınız. Kalıtım yerine kompozisyon kullanın.
Lee

2
Uzatmak ister misiniz LinkedList? "Miras üzerinde kompozisyonu tercih et" dediğinde belirli bir Joshua Bloch'un tavsiyesine (Java koleksiyonları çerçevesini tasarlamada büyük rol oynamış) dikkat etmek isteyebilirsiniz - Belki de LinkedListyığın sınıfınızın içinde olabilirsiniz, ama aslında genişletmeyin?
corsiKa

1
Liskov ikame ilkesini karşılayamayacağını söyleyebilirim, çünkü "yığın bir tür bağlantılı listedir" gerçek bir ifade değildir. "Stack" gerçekten bir arabirimdir (yani kavramsal olarak Java yapısı değil). Yığın edilebilir uygulanan bağlantılı bir listesini içerir. Diğerlerinin söylediği gibi, LinkedListperde arkasında (kompozisyon) ağır kaldırma yapan özel bir veri üyesi kullanırsınız . Bu şekilde, kodunuzun kullanıcıları yanlışlıkla bir Listeye ihtiyaç duydukları bir Yığını kullanamaz veya tam tersi.
Jasmijn

1
Daha akıllıca bir şey olur gibi görünüyor. Eğer bu yapıyordum ben muhtemelen tamamen bunu yapabiliyor gibi bir "yığın" arayüzü uygulamak bağlantılı bir liste sınıfı olurdu. Aksi takdirde, bir yığın bir kavram olduğu için bu yanlış bir yol, bağlantılı bir liste diğer şeyler arasında yığın olarak işlev görebilen bir uygulamadır.
Vality

Yanıtlar:


31

Şimdi push (), pop (), peek () veya top () gibi işlevler sağlayan bir Sınıf Stack var ve bu yöntemleri uygulamak için LinkedList sınıf yöntemlerini genişletiyor. Bu Liskov İkame İlkesinin ihlali midir?

Hayır. Bir alt türe yöntem eklemek mükemmeldir.

Örneğin, Bağlantılı Listenin n'inci konumuna düğüm eklemek için add_after () örneğini düşünün. Bu temel sınıfta yapılabilir, ancak Stack sınıfında yapılamaz.

Bu ise LSP ihlali. LSP, bir alt tip örneklerinin, bir programın istenen özelliklerini değiştirmeden bir süper tip örneklerinin yerine geçmesi gerektiğini söylüyor. Bir alt tür bir yöntemi kaldırırsa, bu yöntemi çağıran herhangi bir kod kilitlenir (veya NoMethodErrorbu satırlar boyunca bir istisna veya başka bir şey alır). Açıkçası, "çökmemesi" arzu edilen bir özelliktir.

Burada son koşullar zayıflıyor mu yoksa yığının en üstüne eklemek için add_after () yöntemini değiştiriyor musunuz?

add_after()Yöntemin bu şekilde değiştirilmesi, Tarih Kuralının ihlalidir (kuralların en önemlisi!) Ve bu nedenle LSP ihlalinin düzeltilmesine yardımcı olmaz.

LinkedList sınıfını kullanarak Stack işlevini nasıl uygularsınız?

Kompozisyon kullanarak.

NOT: Yukarıda yazdığım her şey sadece alt tipleme ve alt sınıflamayı karıştıran diller için geçerlidir! LSP, alt sınıflama ile değil alt tipleme ile ilgilidir . İki şaşırtmak değil bir dil olarak, yapmak mükemmel kabul edilebilir Stackbir alt sınıfını LinkedListbunu bir yapmazlar sürece, alt tipi arasında LinkedList.


9
Tarih Kuralı nedir? İnternette bulamadım.
Zapadlo

10
Bir alt türün bir nesnesini manipüle ederken ve üst türün yöntemleriyle gözlemlerken, üst türün bir nesnesiyle de gözlemlenemeyen bir tarihi gözlemlemek imkansız olmalıdır. Bu kural LSP'yi işlevsel olmayan diller için geçerli kılan kuraldır. Diğer tüm şeyler bundan çok önce biliniyordu. Ön koşul ve son koşul kuralları, işlev türleri için eş ve karşıtlık kurallarının yeniden biçimlendirilmesidir. Geçmiş kuralı, bunların tümünü değiştirilebilir veriler için geçerli kılar. Onsuz, LSP yalnızca tamamen işlevsel diller için yararlı olacaktır.
Jörg W Mittag

2
Wikipedia makalesindeki açıklamanın oldukça iyi olduğunu düşünüyorum: wikipedia.org/wiki/Liskov_substitution_principle Ama her zamanki gibi, orijinal kaynağı gerçekten okumalısınız.
Jörg W Mittag

@ JörgWMittag: Türlerin, “tarih” in hangi gözlemlenip gözlemlenmeyeceğine dair sözleşme garantilerine dahil edilmesinin makul olduğunu düşünürken, her türün her gözlem dizisini üretebilmesinin gerekli olması gerektiğini düşünmüyorum. bu, alt türün bir nesnesi üzerinde mümkün olabilir - sadece üst türün, üst türün tüketicilerinin bu tür dizileri gözlemleme olasılığını belgelediği.
supercat

1

Her şey zaten Jörg W Mittag tarafından ele alındığından, aşağıdaki bölümde biraz ayrıntılı olarak duruyorum:

Burada son koşullar zayıflıyor mu yoksa yığının en üstüne eklemek için add_after () yöntemini değiştiriyor musunuz?

Temel olarak, bazı hiyerarşilerin LSP'yi ihlal edip etmediği sorusu olduğunda, hangi sözleşmeyi yaptığınıza bağlıdır. Peki, hangi sözleşmede add_aftervar? Kulağa hoş geliyorsa da, "n'inci konumda veya üstte bir düğüm ekle" gibi görünüyorsa, iyi olduğunuzdan sonra, post-condition karşılanır, LSP ihlal edilmez. Aksi takdirde bu bir LSP ihlalidir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.