Liskov almashtirish printsipiga misol nima?

Men Liskov almashtirish printsipi (LSP) ob'ektga yo'naltirilgan dizaynning asosiy printsipi ekanligini eshitdim. Bu nima va undan foydalanishga qanday misollar bor?


person NotMyself    schedule 11.09.2008    source manba
comment
LSPga rioya qilish va buzilishning boshqa misollari bu yerda   -  person StuartLC    schedule 15.05.2015
comment
Bu savolning cheksiz ko'p yaxshi javoblari bor va shuning uchun juda keng.   -  person Raedwald    schedule 16.12.2018
comment
12 yil o'tgach, agar siz o'zingizning javobingizni qabul qilmasangiz va boshqasini qabul qilsangiz juda yaxshi bo'lardi, chunki sizning javobingiz afsuski, mutlaqo noto'g'ri va LSP ni tavsiflamaydi, aksincha interfeysning mos kelmasligi. Va bu qabul qilinganligi sababli, bu ko'p odamlarni chalg'itmoqda (yuqori ovozlar soniga ko'ra).   -  person Konrad Rudolph    schedule 13.10.2020
comment
Bu men uchun ishlaydi. Eng mashhur javobga o'tildi.   -  person NotMyself    schedule 13.10.2020
comment
minglab ijobiy ovoz!   -  person Jonas Grønbek    schedule 06.06.2021


Javoblar (33)


LSPni (yaqinda eshitgan podkastda Bob amaki tomonidan berilgan) ko'rsatuvchi ajoyib misol, ba'zida tabiiy tilda to'g'ri eshitiladigan narsa kodda ishlamasligi edi.

Matematikada Square Rectangle hisoblanadi. Darhaqiqat, bu to'rtburchakning ixtisoslashuvidir. "Is a" sizni meros bilan modellashtirishga majbur qiladi. Ammo agar siz kodda Square ni Rectangle dan kelib chiqqan bo'lsangiz, Square dan Rectangle kutilgan har qanday joyda foydalanish mumkin bo'ladi. Bu qandaydir g'alati xatti-harakatlarga olib keladi.

Tasavvur qiling-a, sizning Rectangle tayanch sinfingizda SetWidth va SetHeight usullari bor edi; bu mutlaqo mantiqiy ko'rinadi. Biroq, agar Rectangle ma'lumotnomangiz Square ga ishora qilgan bo'lsa, SetWidth va SetHeight ma'nosi yo'q, chunki birini o'rnatish ikkinchisini unga mos keladigan tarzda o'zgartiradi. Bu holda Square Liskov almashtirish testini Rectangle bilan bajara olmaydi va Square ni Rectangle dan meros qilib olish abstraktsiyasi yomon.

rasm tavsifini shu yerga kiriting

Boshqa bebaho SOLID Principles motivatsion plakatlar.

person m-sharp    schedule 25.02.2009
comment
@m-sharp Agar u o'zgarmas to'rtburchak bo'lsa-chi, shuning uchun SetWidth va SetHeight o'rniga bizda GetWidth va GetHeight usullari mavjud? - person Pacerier; 26.04.2012
comment
Hikoyaning axloqi: o'z sinflaringizni xususiyatlarga emas, balki xatti-harakatlarga asoslangan holda modellang; ma'lumotlaringizni xatti-harakatlarga emas, balki xususiyatlar asosida modellashtiring. Agar u o'zini o'rdak kabi tutsa, bu, albatta, qush. - person Sklivvz; 20.05.2012
comment
Xo'sh, kvadrat haqiqiy dunyoda to'rtburchaklar turidir. Buni kodimizda modellashimiz mumkinmi, bu spetsifikatsiyaga bog'liq. LSP shuni ko'rsatadiki, pastki turdagi xatti-harakatlar asosiy turdagi spetsifikatsiyada belgilangan asosiy turdagi xatti-harakatlarga mos kelishi kerak. Agar to'rtburchak asos turi spetsifikatsiyasi balandlik va kenglikni mustaqil ravishda o'rnatish mumkinligini aytsa, LSP kvadrat to'rtburchakning pastki turi bo'lishi mumkin emasligini aytadi. Agar to'rtburchak spetsifikatsiyasi to'rtburchakning o'zgarmasligini bildirsa, kvadrat to'rtburchakning kichik turi bo'lishi mumkin. Bularning barchasi asosiy tur uchun belgilangan xatti-harakatlarni saqlaydigan kichik tiplar haqida. - person SteveT; 24.09.2012
comment
@Pacerier, agar u o'zgarmas bo'lsa, hech qanday muammo yo'q. Bu erda haqiqiy muammo shundaki, biz to'rtburchaklar emas, balki qayta shakllantiriladigan to'rtburchaklar, ya'ni yaratilgandan keyin kengligi yoki balandligi o'zgartirilishi mumkin bo'lgan to'rtburchaklar (va biz uni hali ham bir xil ob'ekt deb hisoblaymiz). To'rtburchaklar sinfini shu tarzda ko'rib chiqsak, kvadrat qayta shakllantiriladigan to'rtburchak emasligi aniq bo'ladi, chunki kvadratni qayta shakllantirib bo'lmaydi va baribir kvadrat (umuman) bo'ladi. Matematik jihatdan biz muammoni ko'rmayapmiz, chunki o'zgaruvchanlik matematik kontekstda ham mantiqiy emas. - person asmeurer; 20.01.2013
comment
Professor Barbara Liskovning ma'ruzasidan: Subtiplar ob'ektlari o'zini supertiplarniki kabi tutishi kerak. supertipli usullar. - person ruhong; 04.02.2015
comment
Agar kenglik va balandlik sozlamalari tomonidan o'zgartirilishi mumkin bo'lsa, faqat to'rtburchaklar sinfi va maxsus kvadrat sinfi bo'lmasligi kerak. Buning o'rniga, to'rtburchaklar sinfida IsSquare deb nomlangan oluvchi bo'lishi kerak. Qachonki kenglik va balandlik bir xil qiymatlarga ega bo'lsa, IsSquare haqiqatni qaytaradi, aks holda noto'g'ri. Turlar har doim ham statik emas, lekin ba'zida - bu holatda bo'lgani kabi - o'zgarishi mumkin. - person brighty; 10.02.2015
comment
Agar mening meros qilib olgan sinfimning xatti-harakati ota-onadan farq qilmasa (bir xil, ammo boshqacha tarzda sodir bo'lgan holatlar bundan mustasno) nima uchun menga subtyping kerak? Agar ular bazaga mutlaqo o'xshash harakat qilishlari kerak bo'lsa, nima uchun bu bekor qilish usullari kerak? geometriya raqamlari haqida gapirganda: IDrawable Draw() ga ega. Circle:IDrawable's Draw() ning Square:IDrawable's bilan bir xil natija berishini qanday talab qila olasiz? yoki aytaylik, Rotated90DegreesSquare:Kvadrat chizilgan kvadrat bilan bir xilmi? - person jungle_mole; 11.09.2015
comment
Menda printsip haqida bitta savol bor. Agar Square.setWidth(int width) quyidagi tarzda amalga oshirilgan bo'lsa, nima uchun muammo bo'ladi: this.width = width; this.height = width;? Bunday holda, kenglik balandlikka teng bo'lishi kafolatlanadi. - person MC Emperor; 28.10.2015
comment
Motivatsion plakatning ma'nosi yo'q. Bu shunday bo'lishi kerak, agar u o'rdakga o'xshasa, o'rdakdek chayqalsa, lekin batareyaga muhtoj bo'lsa ... nega sizni yana batareyalar qiziqtiradi? Chunki, oxir-oqibat, bu o'rdakning yagona o'rnini boshqa o'rdak (eng yaxshisi, xuddi shunday) ekanligini anglatadi. Bunday radikalizm o'z-o'zidan mag'lub bo'ladi. - person David Tonhofer; 05.01.2016
comment
Kvadrat-to‘rtburchak muammosi Doira-ellips muammosi nomi bilan ham tanilgan. - person mbx; 02.03.2016
comment
To'g'ri yoki noto'g'ri, yaxshi yoki yomon, insonning nuqtai nazariga bog'liq - u kod iste'molchisi yoki kod muallifi tomonidan bo'ladimi. LSP, IMO, iste'molchi tomoniga tegishli. To'g'ri nuqtai nazarni qo'ying, ko'p xatolar to'g'ri ko'rinadi. - person Sudhir; 23.05.2016
comment
Yana bir yechim - to'rtburchaklarni mustaqil kenglik va balandliklarga ega emas, balki tomonlar nisbati saqlovchi sifatida belgilash. - person Ed L; 16.07.2016
comment
Savolga javob bermaganga o'xshaydi. Uni o'qib chiqqandan so'ng, men hali ham LSP nima ekanligini bilmayman (agar afishada ta'rif bo'lmasa, lekin bunday plakatlarning kontekstini hisobga olsak, bu aniq emas). - person iheanyi; 12.08.2016
comment
Men kvadrat misolni ham olmayapman. Qanday qilib setWidth va setHeight kvadratda mantiqiy emas. Siz juda oson tushuntirganingizdek, birini bajarish ikkinchisini nazarda tutadi - bu faqat kvadratning ta'rifi. Bu nima uchun noto'g'ri yoki to'rtburchak o'rniga kvadrat o'rniga mos kelmasligini tushuntirmaydi. - person iheanyi; 12.08.2016
comment
Siz shunchaki setWidth yoki setHeight ni bekor qila olmaysizmi va ta'rifda bir xil parametr va poof bilan boshqa usulni chaqira olmaysizmi, barchasi ishlaydi va xatti-harakatlar izchilmi? - person Ungeheuer; 22.11.2016
comment
@MCEmperor, agar siz Square da setHeight() va setWidth() amallarini o'zgartirsangiz, shuning uchun kodingizdagi Rectangule ishlatadigan joylar Square dan o'tsangiz, endi ishlamaydi va bu LSP haqida asosiy nuqta; - person sdlins; 26.12.2016
comment
Javobingiz uchun rahmat - lekin LSP buzilgan bo'lsa nima bo'ladi? - person BKSpurgeon; 02.01.2017
comment
Biroq, rasm buzilgan LSP ning haqiqiy namunasi EMAS (aslida Reddit hidi keladi va bu biz SO-da hidlashni xohlaydigan narsa emas). Subklasslar har doim super sinflarga qaraganda aniqroq bo'ladi. Biroq, ularning o'ziga xos xususiyatlari LSPni buzishi shart emas. Bu xususiyatlar umumiy shartnomaga ta'sir qiladimi (va buzadimi) degan savol. Batareya bilan ishlaydigan o'rdak mavhum o'rdakning umumiy shartnomasini buzadimi, dizaynning o'ziga xos tafsilotlariga bog'liq. - person AnT; 28.01.2017
comment
Hamma bu kvadrat va to'rtburchakdan foydalanadi, bu dahshatli misol. Siz Balandlik xususiyatini o'rnatish uchun Kenglik xususiyatini bekor qilyapsiz, bu ko'proq yon ta'sirga o'xshaydi. Agar siz odamlarga kenglik va balandlikni aniq belgilashga majbur qilsangiz, bularning barchasi hal qilinadi. - person johnny 5; 01.03.2017
comment
Oxiridagi rasm ham, havola ham buzilgan. Uni tuzatishga qarshimisiz? - person PaulB; 05.06.2017
comment
Rahmat @PaulB. Buni tuzatdi. - person m-sharp; 06.06.2017
comment
Los texniklari hozir men uchun ishlamoqda, @m-sharp. Bu vaqtinchalik uzilishmi yoki hatto mintaqaviymi? Endi 8-versiya hech bo'lmaganda keraksiz ko'rinadi. - person Palec; 07.06.2017
comment
Ajoyib. O'zgartirishni orqaga qaytardi. SO haqiqatan ham yaxshi tahrir tarixiga ega! - person m-sharp; 07.06.2017
comment
Jin ursin, butun Lot Techies sayti endi Maʼlumotlar bazasi xatosi deb nomlangan va faqat maʼlumotlar bazasi ulanishini oʻrnatishda xatolik bilan h1 ni oʻz ichiga olgan bir xil sahifani qaytaradi. Men topdim eng so'nggi WayBack Machine snapshotva unda tasvirlar CC BY-SA bo'yicha litsenziyalanganligi aniq aytilgan. WayBack Machine snapshotiga, shuningdek, asl URL manziliga havola qilishni va rasmni Stack Overflow serverlariga (muharrir orqali) yuklashni tavsiya qilaman. Shunday qilib, uzilishlar postga ta'sir qilmaydi. - person Palec; 10.06.2017
comment
o.setDimensions(width, height) bu muammoni hal qiladi, lekin LSP hali ham buziladi, chunki kvadrat to'rtburchakga qaraganda kuchliroq shartlarga ega (width == height). Sizning postingiz LSP haqida hech narsaga javob bermaydi deb o'ylamayman. - person inf3rno; 09.10.2017
comment
Bu yerda softwareengineering.stackexchange.com/a/244783/1451 usullarini bekor qilish/shartnomalar haqida yaxshi qo'shimcha ma'lumot mavjud. - person BrunoLM; 21.10.2017
comment
To'rtburchak kvadrat turimi yoki kvadrat to'rtburchaklar turimi yoki aksinchami? To'rtburchakni tomonlari teng bo'lmagan kvadrat, kvadratni esa teng tomonlari bo'lgan to'rtburchaklar sifatida aniqlash mumkin. Tomonlari teng bo'lmagan kvadrat kvadrat emas, lekin tomonlari teng bo'lgan to'rtburchak hali ham to'rtburchak va kvadratdir. Shunday qilib, kvadrat qo'shimcha shartnomaga ega bo'lgan to'rtburchaklardir. Shuning uchun kvadrat uchun interfeys to'rtburchaklar bilan bir xil bo'lishi kerak. Bir o'lchamni o'rnatish ikkinchisini o'rnatishi juda mantiqiy. - person ATL_DEV; 15.12.2017
comment
Agar ular o'zgarmas bo'lsa, men hech qanday muammo yo'q deb aytmayman. Bu o'quvchini GetHeight va GetWidth ni ko'rishga majbur qilishi mumkin, agar ular xuddi shu narsani qilishmoqchi. Bu kichik muammo bo'lishi mumkin, lekin baribir buni boshqa yo'l bilan qilish uchun sababdir. - person AustinWBryan; 09.05.2018
comment
Ba'zi kitoblarda %100 qoidasi deyiladimi? - person anilkay; 17.06.2018
comment
@AustinWBryan yo'q, bular yaxshi belgilangan miqdorlar. Kvadratning balandligi ham, kengligi ham bor; ular teng bo'ladi. Agar o'quvchi bu bilan haydab qolsa, ular kod haqida yangi va muhim narsani o'rganishadi yoki ular u erga tegishli emas :) - person Ben Kushigian; 19.06.2018
comment
O'ylaymanki, biz sub-turni alohida holat bilan aralashtirib yuboramiz. Kvadratning xatti-harakati to'rtburchakdan farq qilmaydi. Perimetr, maydon bir xil formulalar yordamida hisoblanishi mumkin. Kvadrat to'rtburchakning yaxshilanishi yoki takomillashtirilishi emas, bu faqat alohida holat. Kvadrat to'rtburchakning pastki sinfi bo'lmasligi kerak, hatto alohida sinf ham bo'lmasligi kerak. - person Mircea Ion; 05.02.2019
comment
@MirceaIon, Square interfeysni soddalashtirish uchun to'rtburchakning pastki sinfi bo'lishi mumkin, masalan, SetWidth va SetHeight ni chaqirishi mumkin bo'lgan SetLength bilan - person alancalvitti; 29.03.2019
comment
To'rtburchakdan Kvadratni olish mumkin, lekin sizda setWidth va setHeight bo'lmasligi kerak. Lekin hech kim sizni to'rtburchaklar qo'ygan zona uchun o'rnatgichlarga ega bo'lishingizga xalaqit bera olmaydi. Bunday holda, Kvadrat zonaning faqat bir qismini to'ldiradi, To'rtburchak esa uni to'liq to'ldiradi. :) - person Alex; 17.04.2019
comment
Iltimos, kimdir kodni yaxshi ko'rishi uchun menga LSP ga amal qilish uchun xuddi shu misolni yana qanday modellashtirish kerakligini aytib bera oladimi? - person Saurabh Goyal; 11.06.2019
comment
Bir marta kvadratlar haqidagi ushbu aniq savol bo'yicha intervyu muvaffaqiyatsiz tugadi. Suhbatdosh mening savolimni rad etdi: bu to'rtburchaklar va kvadratlar bilan nima qilamiz? Bugun men bu ishga ega bo'lmaganimdan xursandman. :) - person Aleksei Guzev; 15.12.2019
comment
Qaysi Bob amaki? :-? - person Yousha Aleayoub; 05.02.2020
comment
@sdlins Men rozi emasman. Kvadrat sinfida setHeight va setWidth xatti-harakatlari ustidan yozilgan MCEmperor kod boshqa Reactangle uchun ishlamasligiga imzo chekkan vaziyatni nomlay olasizmi? - person Murilo; 09.04.2020
comment
Kodni ko'rsatadigan misol va snippetni taqdim etish ancha yaxshi bo'lardi. - person Giorgi Tsiklauri; 06.08.2020
comment
@Murilo Bu bizning 640x480 qutimizni to'ldirishi kerak, shuning uchun r.SetWidth (640); r.SetHeight(480) yoki aksincha, hech qanday farq qilmaydi. Kenglik va balandlikni alohida o'rnatish imkoniyatini taklif qiladigan, lekin aslida buni qilmaydigan har qanday kichik sinf narsalarni buzadi. - person prosfilaes; 13.01.2021
comment
Men SetWidth va SetHeight usullarida topadigan muammo shundaki, ular nafaqat LSP, balki ISP (Interfeyslarni ajratish printsipi) ni ham buzadi, shuning uchun ular Rectangle va SetSize(int) uchun SetSize(int, int) bo'lishi mumkin bo'lgan ikki xil interfeysda ajratilishi kerak. Square uchun, chunki ular boshqacha, Getters o'z joyida qolishi mumkin ... muhokamaga ochiq - person Eugenio Miró; 28.01.2021
comment
O'rdak, batareyalar va nima uchun u LSVni buzadi -›, chunki o'rdaklar, ta'rifiga ko'ra, batareyalarga muhtoj emaslar. Men uchun bu juda aniq va bu hazil ko'rinishidagi metafora, bundan jiddiyroq qabul qilinmasligi kerak. - person Ric Jafe; 17.03.2021
comment
@SaurabhGoyal - Gap shundaki, to'g'ri amalga oshirish bir oluvchining boshqa mulkka nojo'ya ta'siriga ega bo'lmasligi kerak, chunki ota-onada ular birinchi navbatda yo'q edi. Misol uchun, siz individual balandlik va kenglik uchun oluvchilarga ega bo'lolmaysiz va keyin juftlik va bitta to'plamDimentions(x,y) bo'lishi mumkin emas va shu bilan kvadrat misolida Kenglikni o'rnatishda balandlikni o'zgartirishning ushbu o'ziga xos yon ta'siridan qochishingiz mumkin. . Albatta, bunga erishishning ko'plab usullari mavjud. Asosiysi, bolaning xatti-harakati ota-onadan farq qiladi. Bu LSPni buzadigan narsa. - person Ric Jafe; 17.03.2021
comment
Bu menga boshqa misollardan ko'ra ko'proq tushunishga yordam berdi - person Tom; 24.05.2021

Liskov almashtirish printsipi (LSP, lsp) Ob'ektga yo'naltirilgan dasturlash kontseptsiyasida quyidagilar aytiladi:

Ko'rsatkichlar yoki asosiy sinflarga havolalardan foydalanadigan funksiyalar hosila sinflari ob'ektlarini bilmagan holda ishlata olishi kerak.

LSP asosan interfeyslar va shartnomalar, shuningdek, sinfni qachon kengaytirish va maqsadingizga erishish uchun kompozitsiya kabi boshqa strategiyadan foydalanishni qanday hal qilish haqida.

Bu fikrni tasvirlashning eng samarali usuli Head First OOA&Dda bo'ldi. Ular strategiya o'yinlari uchun asos yaratish bo'yicha loyihada ishlab chiquvchi bo'lgan stsenariyni taqdim etadilar.

Ular shunday ko'rinishdagi taxtani ifodalovchi sinfni taqdim etadilar:

Sinf diagrammasi

Barcha usullar X va Y koordinatalarini Tiles ikki o'lchovli massivdagi plitka o'rnini aniqlash uchun parametr sifatida qabul qiladi. Bu o'yinni ishlab chiquvchiga o'yin davomida doskadagi birliklarni boshqarish imkonini beradi.

Kitobda o'yin ramkasi ishi parvozga ega o'yinlarni joylashtirish uchun 3D o'yin taxtalarini ham qo'llab-quvvatlashi kerakligini aytish uchun talablarni o'zgartiradi. Shunday qilib, Board ni kengaytiruvchi ThreeDBoard sinfi kiritildi.

Bir qarashda bu yaxshi qarorga o'xshaydi. Board Height va Width xossalarini va ThreeDBoard Z o'qini ta'minlaydi.

U Board dan meros qolgan barcha boshqa a'zolarni ko'rganingizda buziladi. AddUnit, GetTile, GetUnits va boshqalar uchun usullar Board sinfida X va Y parametrlarini oladi, lekin ThreeDBoard uchun ham Z parametr kerak.

Shunday qilib, siz ushbu usullarni Z parametri bilan qayta qo'llashingiz kerak. Z parametri Board sinfiga kontekstga ega emas va Board sinfidan meros qilib olingan usullar o'z ma'nosini yo'qotadi. ThreeDBoard sinfini Board asosiy klassi sifatida ishlatishga urinayotgan kod birligi omadsiz bo'ladi.

Ehtimol, biz boshqa yondashuvni topishimiz kerak. Board ni kengaytirish o'rniga ThreeDBoard Board ob'ektdan iborat bo'lishi kerak. Z o'qi birligi uchun bitta Board ob'ekt.

Bu bizga inkapsulyatsiya va qayta foydalanish kabi ob'ektga yo'naltirilgan yaxshi tamoyillardan foydalanishga imkon beradi va LSPni buzmaydi.

person NotMyself    schedule 11.09.2008
comment
Shunga oʻxshash, ammo soddaroq misol uchun Vikipediyadagi Daire-ellips muammosi ga qarang. - person Brian; 21.10.2011
comment
@NotMySelf dan iqtibos: Menimcha, misol shunchaki ThreeDBoard kontekstida kengashdan meros olish mantiqiy emasligini va barcha usul imzolari Z o'qi bilan ma'nosiz ekanligini ko'rsatish uchundir. - person Contango; 05.06.2013
comment
@Kris Ammermandan iqtibos: LSPga rioya qilishni baholash merosni emas, balki mavjud funksionallikni kengaytirish uchun kompozitsiya qachon mosroq mexanizm ekanligini aniqlashda ajoyib vosita bo'lishi mumkin. - person Contango; 05.06.2013
comment
Shunday qilib, agar biz Child sinfiga boshqa usul qo'shsak, lekin Ota-onaning barcha funktsiyalari Child sinfida mantiqiy bo'lsa, bu LSPni buzadimi? Bir tomondan, biz Boladan foydalanish interfeysini biroz o'zgartirganimiz uchun, boshqa tomondan, agar biz bolani ota-onaga aylantirsak, ota-onadan kutilgan kod yaxshi ishlaydi. - person Nickolay Kondratyev; 18.06.2013
comment
Bu Liskovga qarshi misol. Liskov bizni kvadratdan to'rtburchaklar chiqarishga majbur qiladi. Ko'proq parametrlar sinfi kamroq parametrlar sinfidan. Va bu yomon ekanligini yaxshi ko'rsatdingiz. Javob sifatida belgilangan va liskov savoliga anti-liskov javobiga 200 marta ko'tarilgan bo'lish haqiqatan ham yaxshi hazil. Liskov printsipi haqiqatan ham noto'g'ri? - person Gangnus; 18.10.2015
comment
@Contango Va bu erda berilgan javobga ko'ra, meros yaxshi bo'lgan misol keltira olasizmi? - person Gangnus; 18.10.2015
comment
Men merosning noto'g'ri ishlashini ko'rdim. Mana bir misol. Asosiy sinf 3DBoard va olingan sinf Board bo'lishi kerak. Kengash hali ham Max(Z) = Min(Z) = 1 Z o'qiga ega - person Paulustrious; 05.08.2017
comment
@Nickolay Kondratyev, ha, LSP ni buzmaydi, uni o'zingiz hal qildingiz. - person brgs; 12.07.2018
comment
Kompozitsiyadan foydalanmasdan muammoni hal qila olamizmi? Menimcha, buni GetUnits(int x, int y) ning imzosini GetUnits(Position pos) ga o'zgartirish orqali amalga oshirish mumkin va xuddi shu narsa boshqa funktsiyalar uchun ham amal qiladi. Shunday qilib, u LSPni buzmaydi. Agar xato qilsam, meni tuzating. - person du369; 22.04.2020
comment
@Paulustrious bu ochiq-yopiq tamoyilni buzadi. FourDBoardni xohlasangiz nima bo'ladi? Buni ThreeDBoard-ning tayanch sinfiga aylantirishingiz kerak, ya'ni ThreeDBoard dasturini amalga oshirishni o'zgartirish orqali (siz hatto kirish huquqiga ham ega bo'lmaysiz). - person Jupiter; 19.07.2020
comment
Numpy bu aniq muammoni ndarray bilan hal qildi. 3 o'lchovli, 2 o'lchovli va 1 o'lchovli massivlar umumlashtirilgan n o'lchovli massivning barcha ixtisoslashuvidir. Matematiklar buni bir necha asr oldin aniqlaganlar. Dasturchilar asta-sekin algebrani qayta ixtiro qilmoqdalar. - person Adam Acosta; 22.12.2020

O'rnini bosish - bu ob'ektga yo'naltirilgan dasturlash printsipi bo'lib, agar kompyuter dasturida agar S T ning kichik turi bo'lsa, u holda T tipidagi ob'ektlar S tipidagi ob'ektlar bilan almashtirilishi mumkin.

Keling, Java-da oddiy misol keltiramiz:

Yomon misol

public class Bird{
    public void fly(){}
}
public class Duck extends Bird{}

O'rdak qush bo'lgani uchun ucha oladi, lekin bu haqda nima deyish mumkin:

public class Ostrich extends Bird{}

Tuyaqush qush, lekin u ucha olmaydi, Tuyaqush klassi Qushlar sinfining kichik turi, lekin u chivin usulidan foydalana olmasligi kerak, demak biz LSP tamoyilini buzyapmiz.

Yaxshi namuna

public class Bird{}
public class FlyingBirds extends Bird{
    public void fly(){}
}
public class Duck extends FlyingBirds{}
public class Ostrich extends Bird{} 
person Maysara Alhindi    schedule 04.07.2017
comment
Yaxshi misol, lekin mijozda Bird bird bo'lsa nima qilasiz. Chivindan foydalanish uchun ob'ektni FlyingBirds-ga tashlashingiz kerak, bu yaxshi emasmi? - person Moody; 20.11.2017
comment
Yo'q. Agar mijozda Bird bird bo'lsa, demak u fly() dan foydalana olmaydi. Bo'ldi shu. Duck belgisidan o'tish bu faktni o'zgartirmaydi. Agar mijozda FlyingBirds bird bo'lsa, u Duck dan o'tgan bo'lsa ham, u har doim bir xil tarzda ishlashi kerak. - person Steve Chamaillard; 18.02.2018
comment
Bu interfeyslarni ajratish uchun yaxshi namuna bo'lib xizmat qilmaydimi? - person Saharsh; 05.03.2019
comment
Ajoyib misol Rahmat odam - person Abdelhadi Abdo; 28.05.2019
comment
"Flyable" interfeysidan foydalanish haqida nima deyish mumkin (yaxshiroq nom topa olmayman). Shunday qilib, biz o'zimizni ushbu qattiq ierarxiyaga topshirmaymiz. - person Thirdy; 28.05.2019
comment
Singan qanotlarni davolovchi veterinar yomon misolni ko'radi. Ba'zi uchmaydigan qush turlari o'z yo'lida ucha oladi (tovuq bu erda gibriddir). Shuningdek, uchish qobiliyati evolyutsiyada o'zgaradi. Standart NULL-ga ega bo'lgan uchish usuli yaxshi qaror bo'lib, keyinchalik bekor qilinadi. - person Sławomir Lenart; 31.01.2020
comment
Shunday qilib, ota-onalar sinfi faqat o'z bolalarining xatti-harakatlarini cheklamasdan, balki butun bolalari bo'lgan xatti-harakatlarni o'z ichiga olishi kerak. - person Ari; 25.02.2020
comment
Nihoyat, bir soatlik qidiruvdan keyin tushundim! - person Boshra N; 17.11.2020

LSP invariantlarga tegishli.

Klassik misol quyidagi psevdokod deklaratsiyasi bilan berilgan (amalga oshirishlar o'tkazib yuborilgan):

class Rectangle {
    int getHeight()
    void setHeight(int value) {
        postcondition: width didn’t change
    }
    int getWidth()
    void setWidth(int value) {
        postcondition: height didn’t change
    }
}

class Square extends Rectangle { }

Endi interfeys mos kelsa-da, bizda muammo bor. Sababi, biz kvadrat va to'rtburchaklarning matematik ta'rifidan kelib chiqadigan invariantlarni buzdik. Qabul qiluvchilar va sozlagichlarning ishlash usuli, Rectangle quyidagi invariantni qondirishi kerak:

void invariant(Rectangle r) {
    r.setHeight(200)
    r.setWidth(100)
    assert(r.getHeight() == 200 and r.getWidth() == 100)
}

Biroq, bu o'zgarmas (shuningdek, aniq postshartlar) Square ning to'g'ri bajarilishi bilan buzilishi kerak, shuning uchun u Rectangle ning haqiqiy o'rnini bosmaydi.

person Konrad Rudolph    schedule 12.09.2008
comment
Va shuning uchun biz aslida modellashni xohlashimiz mumkin bo'lgan har qanday narsani modellashtirish uchun OO dan foydalanish qiyin. - person DrPizza; 30.11.2009
comment
@DrPizza: Albatta. Biroq, ikkita narsa. Birinchidan, bunday munosabatlar to'liq bo'lmasa ham yoki murakkabroq aylanma yo'llardan foydalangan holda OOPda modellashtirilishi mumkin (qaysi muammoingizga mos keladiganini tanlang). Ikkinchidan, yaxshiroq alternativa yo'q. Boshqa xaritalash/modellashda bir xil yoki shunga o'xshash muammolar mavjud. ;-) - person Konrad Rudolph; 30.11.2009
comment
@KonradRudolph, bu yaxshi misol. Square ni e'lon qilishning to'g'ri yo'li qanday? - person ca9163d9; 24.01.2012
comment
@NickW Ba'zi hollarda (lekin yuqorida emas) oddiygina meros zanjirini o'zgartirishingiz mumkin - mantiqiy aytganda, 2D nuqta - bu uchinchi o'lchov e'tiborga olinmaydigan 3D nuqta (yoki 0 - barcha nuqtalar bir xil tekislikda yotadi). 3D maydoni). Lekin bu, albatta, amaliy emas. Umuman olganda, bu meros haqiqatan ham yordam bermaydigan va sub'ektlar o'rtasida tabiiy munosabatlar mavjud bo'lmagan holatlardan biridir. Ularni alohida modellashtiring (hech bo'lmaganda men yaxshiroq yo'lni bilmayman). - person Konrad Rudolph; 24.01.2012
comment
OOP ma'lumotlarni emas, balki xatti-harakatlarni modellashtirish uchun mo'ljallangan. Sizning sinflaringiz LSPni buzishdan oldin ham inkapsulyatsiyani buzadi. - person Sklivvz; 20.05.2012
comment
@Sklivvz Men roziman. Qisqacha misol keltirish qiyin edi va bu LSP aktsiyadorlik namunasidir (siz uni bir nechta kitoblarda topasiz). Lekin ha, umumiy bo'lsa-da, bu yaxshi OOPdan uzoqdir. - person Konrad Rudolph; 20.05.2012
comment
setHeight() va setWidth() usullari mavjud bo'lishiga yo'l qo'ymaslik kerak, chunki bu sinfni o'zgaruvchan qiladi. Biroq, agar ular mavjud bo'lsa, faqat throw NotSupportedException() / NotImplementedException() yoki shunga o'xshash narsa bo'lishi mumkin. - person Leonid; 03.07.2012
comment
@Leonid Qaysidir ma'noda, bu ham shartnomani buzadi, chunki u "imzo" ni o'zgartiradi (ya'ni, funktsiyadan chiqishning mumkin bo'lgan usullari). Endi, ba'zi ramkalar (ahem .NET …) muntazam ravishda ushbu marshrutdan foydalanadi, lekin men buni juda yomon interfeys dizayni deb hisoblayman. - person Konrad Rudolph; 03.07.2012
comment
Bu erda LSP qanday buzilganligini tushunmayapman. Invariant getheight va getwidth o'rnatilgan balandlikni va belgilangan kenglikni qaytarishi kerakligini bildiradi, bu ob-havo to'rtburchaklar kvadrat yoki to'rtburchak bo'lishidan qat'iy nazar har doim to'g'ri bo'ladi. Agar mijoz turli balandlik va kenglikni o'rnatsa, u ob'ekt kvadrat emasligini aniq biladi. Xuddi shunday, agar mijoz ob'ekt kvadrat ekanligini bilsa, u teng balandlik va kenglikni o'rnatadi. To'rtburchaklar sinfida ikkita funktsiya maydoni va perimetri bo'lsa, to'rtburchaklar kvadrat bo'ladimi yoki yo'qmi, funktsiyalar to'g'ri ishlaydi. Xo'sh, bu qanday qilib LSPni buzadi? - person nurabha; 05.06.2013
comment
@nurabha "ob-havo to'rtburchaklar kvadrat yoki to'rtburchak bo'lishidan qat'i nazar, har doim to'g'ri" - noto'g'ri. To'g'ri kodlangan square bilan bu har doim ham to'g'ri emas, ikkala o'rnatuvchi ham kenglik va balandlikni tiklashi kerak, aks holda ular kvadratning (ko'zda tutilgan) invariantlarini saqlab qolmaydi. Boshqacha qilib aytganda: sizda nomuvofiq turdagi tizim mavjud va siz buni hech qachon xohlamaysiz. - person Konrad Rudolph; 06.06.2013
comment
@nurabha To'rtburchakda ikkita funktsiya maydoni va perimetri bir xil muammoga olib keladi. SetArea(4); SetPerimeter(10); oddiy to'rtburchak modelni 1x4 to'rtburchak qiladi. Qo'ng'iroqlar Square sinf modelini avval 2x2 qiladi, keyin esa sqrt(10)xsqrt(10) kvadratga o'zgaradi yoki InvalidOperationException yoki boshqa narsalarni tashlaydi. - person Wolfzoon; 07.08.2016
comment
Haqiqiy invariantlar bo'lmasa, ularni qanday qilib buzgan bo'lishingiz mumkin? Qaysi variantlar buzilganligini (yoki mos kelishini) qanday bilish mumkin? - person iheanyi; 12.08.2016
comment
@iheanyi Siz invariantlarni aniq ko'rsatishingiz kerak (aka. tasdiqlar yoki turdagi tizimdan foydalanish) yoki siz ishlayotgan domenni bilishingiz kerak. Biz to'rtburchaklar va kvadratlar qanday aniqlanishini bilamiz, shuning uchun ular qanday invariantlarni qo'llashini bilamiz. - person Konrad Rudolph; 13.08.2016
comment
Men roziman - cheklovlar yoki o'zgarmasliklar aniq bo'lishi kerak yoki ular tizim tomonidan sizni majburlashi kerak. Ammo, sizning misolingizga asoslanib, meni siz aytib o'tgan invariant bilan kvadrat sinf yozishga majbur qiladigan hech narsa yo'q. O'ylaymanki, o'zgarmaslarni muhokama qilishda nazarda tutilgan narsalarni olib tashlash uchun javobingizni yangilashni taklif qilaman, ular muammoni keltirib chiqaradigan haqiqiy cheklovlardir. - person iheanyi; 14.08.2016
comment
LSP olingan ob'ekt nima qilishini bilmasligi kerak, faqat olingan ob'ektlar asosiy sinf shartnomasini hurmat qiladi. Masalan, Kvadratda SetDepth(int d) => throw exception bo'lishi mumkin. Lekin men hayronman... to'rtburchak H=W ni talab qilmaydigan maxsus kvadrat turimi? Shu bilan bir qatorda..To‘rtburchak ⇒ Trapetsiya ⇒ Paralelogramma. - person Paulustrious; 05.08.2017
comment
Shu bilan bir qatorda..Quadrilateral ⇒ Trapezoid ⇒ Parallelogram. To'rtburchak va kvadrat oxir-oqibat hosil bo'ladi. Paralelogrammadan, garchi Paralelogram ⇒ Romb ⇒ Kvadrat bo'lar edi. O'zingizning hosilalaringizni to'g'ri olish ma'lumotlar bazasi jadvallarini loyihalash kabidir. Boshida xatoga yo'l qo'ying va siz buzg'unchilikka ketyapsiz - person Paulustrious; 05.08.2017
comment
To'rtburchak uchun Kvadrat turini meros qilib olish yoki Square va Rectangle birodarlar sinfiga ega bo'lish mantiqiyroqmi? - person AustinWBryan; 09.05.2018
comment
@AustinWBryan Siz ushbu muammodan qochgan bo'lar edingiz, lekin munosabatlar haqiqatan ham mantiqiy emas: meros modellari "a" munosabatlari va "har bir to'rtburchak - kvadrat" noto'g'ri (va natijada siz boshqasiga duch kelasiz) Birini boshqasiga almashtirib bo'lmaydigan muammolar). Bu boshqa tomondan to'g'ri ("har bir kvadrat - to'rtburchak"), shuning uchun LSPni buzadigan kod yozish juda jozibali. - person Konrad Rudolph; 09.05.2018
comment
@KonradRudolph Xo'sh, ularni Shape yoki Parallelogram yoki boshqa narsalarni meros qilib olgan birodarlar sinflari sifatida saqlash yaxshiroqmi? - person AustinWBryan; 09.05.2018
comment
@AustinWBryan Ha; Men bu sohada qancha vaqt ishlagan bo'lsam, interfeyslar va mavhum asosiy sinflar uchun merosdan, qolganlari uchun esa kompozitsiyadan shunchalik ko'p foydalanaman. Bu ba'zan biroz ko'proq ish (donolik bilan yozish), lekin u ko'plab muammolardan qochadi va boshqa tajribali dasturchilar tomonidan keng tarqalgan tavsiyalarga ega. - person Konrad Rudolph; 09.05.2018
comment
@KonradRudolph Voy, men hech qanday tasavvurga ega emas edim, ammo oxirgi loyihamda men juda ko'p merosdan foydalanish muammolarini boshdan kechirdim. Men ba'zi hosila sinflarga boshqa hosila sinflarning xususiyatlarini berishni xohlayotganimni angladim va buni qilishning iloji yo'q. Sizningcha, faqat mavhum sinflar bolalarga ega bo'lishi kerakmi? - person AustinWBryan; 09.05.2018
comment
@AustinWBryan Ko'pincha, ha. Bu mashhur Effektiv C++ kitoblarining qoidalaridan biri bo'lib, umumiyroq qoida, Mersohlik ustidan kompozitsiya o'ziga xos Vikipediya sahifasi. - person Konrad Rudolph; 09.05.2018
comment
@KonradRudolph Voy, rahmat, men buni tekshirib ko'raman. Ushbu kitobni C# dasturini ishlab chiqish, tuzilmalar va dizayn naqshlarini o'rganish uchun o'qishga arziydimi? - person AustinWBryan; 09.05.2018
comment
@AustinWBryan Ehtimol, yo'q, afsuski; u C++ uchun juda xosdir. Bill Vagnerning Effektiv C# shunga o'xshash naqshga amal qiladi. - person Konrad Rudolph; 10.05.2018
comment
@ca9163d9 Square ni Rectangle dan modellashtirish uchun polimorfik yondashuv shart bo'lmasa, men Rectangle ob'ektini oladigan SquareDecorator ni qo'llab-quvvatlayman. Siz yoki boshqa birov bu haqda qanday fikrda? - person Reuel Ribeiro; 11.01.2019
comment
@ReuelRibeiro Bu haddan tashqari muhandislik yo'nalishiga kiradi; ko'pincha Shape dan meros bo'lishi mumkin bo'lgan ortogonal sinflarni taqdim etish yaxshiroqdir. Ya'ni, sizning yondashuvingiz, albatta, ko'plab real hayotda foydalanish holatlarida to'g'ri echimdir. - person Konrad Rudolph; 11.01.2019
comment
Bu LSPni buzishning yaxshi namunasi ekanligiga ishonchim komil emas. Men bu qandaydir kanonik misol ishlatilganligini tushunaman, lekin buzilishni isbotlash uchun ishlatiladigan da'vo ochiq va yopiq emas. Ha, kodni o'qiganingizda, bu aniq ko'rinadi. Men shunchaki kenglik va balandlikni o'rnatdim, nega balandlik men o'rnatganimdek emas? Ammo kenglik va balandlikni o'rnatish ikkita alohida operatsiya bo'lib, bizda xususiyatlarni ochib berishdan ko'ra, xususiyatlarni o'rnatish usullari mavjudligining sababi shundaki, biz o'z invariantlarimizni saqlab qolishimiz mumkin, bu esa yon ta'sirga olib kelishi mumkin. - person wired_in; 13.10.2020
comment
Aslini olganda, men aytmoqchimanki, bu qoidabuzarlik bo'lishi mumkin bo'lsa-da, bu aniq emas va shuning uchun bu tushunchani o'rganishga harakat qilayotgan odamlar uchun misol sifatida ishlatilmasligi kerak. - person wired_in; 13.10.2020
comment
@wired_in Qayerdan kelayotganingizni ko'raman, lekin sizning sharhingiz misolning o'ziga xos kontekstini e'tiborsiz qoldirmoqda. Ya'ni, biz har qanday eski ob'ekt turiga faqat eski sozlagichni chaqirmaymiz. Biz to'rtburchakning kengligi va balandligini aniq belgilayapmiz. Va bu bilvosita umidlar (yashirin shartnoma) bilan birga keladi. (Yashirin) kutish kenglikni o'zgartirish balandlikni o'zgartirmaydiva aksincha. Ushbu shartnomani o'zgartirish uchun sabablar bor (oxir-oqibat, kvadrat shunday qiladi!). Lekinumumanbu tabiiy kutishlar. O'zgartirish (kvadrat bilan) bu umumiylikni buzadi. - person Konrad Rudolph; 13.10.2020
comment
@KonradRudolph Men tasdiqning To'rtburchak kontekstida ekanligini e'tibordan chetda qoldirmadim va bu LSP ning buzilishi emasligini hech qachon aytmaganman. To'rtburchakning kengligini o'zgartirish balandlikni o'zgartira olmaydi va aksincha, to'g'ridan-to'g'ri shartnoma mavjudligi umuman aniq emas. Kenglikni o'zgartirish balandlikni o'zgartirishdan alohida operatsiya bo'lganligi sababli, to'rtburchak sifatida kenglik yoki balandlik alohida o'zgartirilganda kvadrat o'z o'zgarmaslarini amalga oshira olmaydi, degan yashirin shartnomani ko'rmayapman. - person wired_in; 13.10.2020
comment
@KonradRudolph Sizning namunangiz ikkita alohida operatsiyani birlashtirib, kenglik va balandlikni bir vaqtning o'zida o'rnatishga majbur qildi, lekin to'rtburchakning haqiqiy shartnomasida bu operatsiyalar alohida bo'lib, bu butun misolni talqin qilish mashqi qiladi. LSPning aniq buzilishi - person wired_in; 13.10.2020
comment
@wired_in “Men yashirin kontraktni ko‘rmayapman” — Siz uni ko‘rmayapsiz, chunki u so‘zsiz. Boshqa qiymat o'zgartirilmasligini ta'minlaydigan Rectangle tayanch sinf sozlagichlariga tasdiqlar qo'shish orqali buni aniq qilishingiz mumkin. Ammo kvadratlarning boshqa so'zsizkontraktga ega bo'lishi aynan nima uchun bu LSP buzilishidir: ikkalasi ham yakka holda amal qiladi, lekin kvadrat to'rtburchakning to'g'ri kichik turi emas, chunki ularning yashirin shartnomalari. t mos keladi. - person Konrad Rudolph; 13.10.2020
comment
@wired_in Men Rectangle sinfi haqidagi deklaratsiyamga aniq postshartlarni qo'shdim. Ammo adolatli ogohlantirish: men ularni yana olib tashlashim mumkin, chunki ular sun'iy va har qanday holatda invariant misol usuli bilan olingan. Bundan tashqari, LSP o'zining asl ta'rifiga ko'ra, nafaqat aniq emas, balki yashirin invariantlarga ham tegishli. Shartlarsiz asl misol LSPning asl, rasmiy ta'rifiga juda mos edi. - person Konrad Rudolph; 13.10.2020
comment
@KonradRudolph Muammo shundaki, yashirin invariantlar bahsli. Ular toshga o'rnatilishi shart emas. Bu holatda yashirin invariant bo'lgan narsa haqidagi talqiningiz juda ko'p fikrga ega va ilova kontekstiga asoslangan. - person wired_in; 19.10.2020
comment
@KonradRudolph Men setHeight() va setWidth() mustaqil operatsiyalar bo'lganligi sababli, ularning har biri o'z-o'zidan hech qanday invariantning buzilishi emasligini ta'kidlashim mumkin. Mustaqil operatsiyalarni bitta operatsiya bo'lishga majburlamoqchi bo'lganingizdagina, sizning fikringizcha, yashirin o'zgarmas narsaga bo'lgan qarashingiz ko'rinadi. Shunday qilib, eng yaxshi holatda, bu LSP buzilishi uchun zaif holat - person wired_in; 19.10.2020
comment
@wired_in “Mustaqil operatsiyalarni bitta operatsiya qilishga majburlamoqchi bo‘lganingizdagina bo‘ladi” — Yo‘q, biz ularni bitta operatsiya bo‘lishga majbur qilmayapmiz — ular aniq bir operatsiya emas. Biz majburlayotgan narsa invariantya'ni ob'ekt holati haqidagi tasdiqlardir. Va yana, bu LSPning butun nuqtasi: invariantlar. Bu operatsiyalar haqida emas, balki invariantlar haqida. - person Konrad Rudolph; 19.10.2020

Robert Martin ajoyib qog'ozga ega. Liskov almashtirish printsipi. Bu tamoyilni buzish mumkin bo'lgan nozik va unchalik nozik bo'lmagan usullarni muhokama qiladi.

Qog'ozning ba'zi tegishli qismlari (ikkinchi misol juda zichlashtirilganligiga e'tibor bering):

LSP buzilishining oddiy misoli

Ushbu printsipning eng ko'zga ko'ringan buzilishidan biri ob'ekt turiga qarab funktsiyani tanlash uchun C++ Run-Time Type Information (RTTI) dan foydalanishdir. ya'ni:

void DrawShape(const Shape& s)
{
  if (typeid(s) == typeid(Square))
    DrawSquare(static_cast<Square&>(s)); 
  else if (typeid(s) == typeid(Circle))
    DrawCircle(static_cast<Circle&>(s));
}

Shubhasiz, DrawShape funksiyasi yomon shakllangan. U Shape sinfining barcha mumkin bo'lgan hosilalari haqida bilishi kerak va har safar Shape ning yangi hosilalari yaratilganda uni o'zgartirish kerak. Haqiqatan ham, ko'pchilik bu funktsiyaning tuzilishini ob'ektga yo'naltirilgan dizayn uchun antema deb biladi.

Kvadrat va to'rtburchak, yanada nozik qoidabuzarlik.

Biroq, LSPni buzishning boshqa, ancha nozik usullari mavjud. Quyida tavsiflanganidek Rectangle sinfidan foydalanadigan dasturni ko'rib chiqing:

class Rectangle
{
  public:
    void SetWidth(double w) {itsWidth=w;}
    void SetHeight(double h) {itsHeight=w;}
    double GetHeight() const {return itsHeight;}
    double GetWidth() const {return itsWidth;}
  private:
    double itsWidth;
    double itsHeight;
};

[...] Tasavvur qiling-a, bir kun foydalanuvchilar to'rtburchaklar bilan bir qatorda kvadratlarni ham manipulyatsiya qilish qobiliyatini talab qilishadi. [...]

Shubhasiz, kvadrat barcha oddiy niyat va maqsadlar uchun to'rtburchakdir. ISA munosabatlari mavjud bo'lganligi sababli, Square sinfini Rectangle dan olingan deb modellashtirish mantiqan to'g'ri. [...]

Square SetWidth va SetHeight funksiyalarini meros qilib oladi. Bu funksiyalar Square uchun mutlaqo mos emas, chunki kvadratning kengligi va balandligi bir xil. Bu dizayn bilan bog'liq muammo borligini ko'rsatadigan muhim ishora bo'lishi kerak. Biroq, muammoni chetlab o'tishning bir yo'li bor. Biz SetWidth va SetHeight ni bekor qilishimiz mumkin [...]

Ammo quyidagi funktsiyani ko'rib chiqing:

void f(Rectangle& r)
{
  r.SetWidth(32); // calls Rectangle::SetWidth
}

Agar biz Square ob'ektiga havolani ushbu funktsiyaga o'tkazsak, Square ob'ekti buziladi, chunki balandlik o'zgarmaydi. Bu LSPning aniq buzilishi. Funktsiya uning argumentlarining hosilalari uchun ishlamaydi.

[...]

person Phillip Wells    schedule 12.09.2008
comment
Juda kech, lekin men bu maqoladagi qiziqarli iqtibos deb o'yladim: Now the rule for the preconditions and postconditions for derivatives, as stated by Meyer is: ...when redefining a routine [in a derivative], you may only replace its precondition by a weaker one, and its postcondition by a stronger one. Agar bolalar sinfining oldingi sharti ota-onalar sinfining oldingi shartidan kuchliroq bo'lsa, siz shartni buzmasdan bolani ota-onaga almashtira olmaysiz. . Shuning uchun LSP. - person user2023861; 11.02.2015
comment
@ user2023861 Siz juda haqsiz. Bunga asoslanib javob yozaman. - person inf3rno; 09.10.2017

LSP ba'zi kodlar T turdagi usullarni chaqiradi deb o'ylasa, kerak bo'ladi va S turdagi usullarni bilmagan holda chaqirishi mumkin, bu erda S extends T (ya'ni, S T supertipini meros qilib oladi, undan kelib chiqadi yoki uning pastki turi hisoblanadi).

Masalan, T tipidagi kirish parametriga ega funksiya S turdagi argument qiymati bilan chaqirilganda (ya'ni chaqirilganda) bu sodir bo'ladi. Yoki T tipidagi identifikatorga S tipidagi qiymat tayinlangan bo'lsa.

val id : T = new S() // id thinks it's a T, but is a S

LSP T (masalan, Rectangle) tipidagi usullar uchun kutishlarni (ya'ni o'zgarmaslarni) talab qiladi, buning o'rniga S (masalan, Square) tipidagi usullar chaqirilganda buzilmasligi kerak.

val rect : Rectangle = new Square(5) // thinks it's a Rectangle, but is a Square
val rect2 : Rectangle = rect.setWidth(10) // height is 10, LSP violation

Hatto oʻzgarmas maydonlari boʻlgan tur ham oʻzgarmaslarga ega, masalan. o'zgarmas To'rtburchak o'rnatuvchilar o'lchamlarni mustaqil ravishda o'zgartirishni kutadilar, ammo o'zgarmas Kvadrat o'rnatuvchilar bu taxminni buzadi.

class Rectangle( val width : Int, val height : Int )
{
   def setWidth( w : Int ) = new Rectangle(w, height)
   def setHeight( h : Int ) = new Rectangle(width, h)
}

class Square( val side : Int ) extends Rectangle(side, side)
{
   override def setWidth( s : Int ) = new Square(s)
   override def setHeight( s : Int ) = new Square(s)
}

LSP S kichik turining har bir usuli kontravariant kirish parametr(lar)i va kovariant chiqishiga ega bo'lishini talab qiladi.

Kontravariant dispersiya meros yoʻnalishiga zid ekanligini bildiradi, yaʼni S kichik turidagi har bir kirish parametrining Si turi bir xil boʻlishi yoki Ti turidagi supertip boʻlishi kerak. supertipning mos keladigan usulining mos keladigan kirish parametri T.

Kovariatsiya deganda dispersiya merosning bir xil yo‘nalishida bo‘ladi, ya’ni So turi, S kichik turining har bir usulining chiqishi bir xil bo‘lishi yoki mos keladigan To tipidagi kichik turi bo‘lishi kerak. supertipning mos keladigan usulining chiqishi T.

Buning sababi, agar qo'ng'iroq qiluvchi uni T turiga ega deb hisoblasa, u T usulini chaqiradi deb o'ylasa, u Ti tipidagi argument(lar)ni taqdim etadi va chiqishni To turiga tayinlaydi. U haqiqatda S ning mos keladigan usulini chaqirganda, har bir Ti kirish argumenti Si kirish parametriga, So chiqishi esa To turiga tayinlanadi. Shunday qilib, agar Si kontravariant bo'lmasa, w.r.t. Ti ga, keyin esa Xi kichik turi - bu Si ning pastki turi bo'lmaydi - Ti ga tayinlanishi mumkin.

Bundan tashqari, turdagi polimorfizm parametrlari (ya'ni, generiklar) bo'yicha ta'rif joyidagi tafovut izohlariga ega bo'lgan tillar uchun (masalan, Scala yoki Seylon) T turdagi har bir parametr uchun dispersiya izohining ko- yoki qarama-qarshi yo'nalishi tur parametrining turiga ega bo'lgan har bir kirish parametri yoki chiqishiga (T ning har bir usulidan) mos ravishda qarama-qarshi yoki bir xil yo'nalish.

Bundan tashqari, funktsiya turiga ega bo'lgan har bir kirish parametri yoki chiqish uchun talab qilinadigan farq yo'nalishi teskari bo'ladi. Ushbu qoida rekursiv ravishda qo'llaniladi.


Subtyping mos keladi bu erda o'zgarmaslarni sanab o'tish mumkin.

Invariantlarni kompilyator tomonidan amalga oshirilishi uchun qanday modellashtirish bo'yicha ko'plab tadqiqotlar olib borilmoqda.

Typestate (3-betga qarang) e'lon qiladi va amalga oshiradi holat invariantlari turiga ortogonal. Shu bilan bir qatorda, invariantlarni tasdiqlarni turlarga aylantirish orqali amalga oshirish mumkin. Masalan, faylni yopishdan oldin ochiqligini tasdiqlash uchun File.open() faylda mavjud bo'lmagan close() usulini o'z ichiga olgan OpenFile turini qaytarishi mumkin. Yana bir misol tic-tac-toe API bo'lishi mumkin. kompilyatsiya vaqtida invariantlarni qo'llash uchun yozishdan foydalanish. Turing tizimi hatto Turing-to'liq bo'lishi mumkin, masalan. Scala. Bog'liq terilgan tillar va teorema isbotlari yuqori tartibli tiplash modellarini rasmiylashtiradi.

mavhum kengaytma uchun semantika zaruriyati tufayli men shuni kutaman. Invariantlarni modellashtirish uchun yozishdan foydalanish, ya'ni birlashtirilgan yuqori tartibli denotatsion semantika Typestatedan ustundir. "Kengaytma" muvofiqlashtirilmagan, modulli rivojlanishning cheklanmagan, almashtirilgan tarkibini anglatadi. Menimcha, kengayadigan kompozitsiya uchun bir-biri bilan birlashtirilib bo'lmaydigan umumiy semantikani ifodalash uchun ikkita o'zaro bog'liq modelga (masalan, turlar va Typestate) ega bo'lish, menimcha, birlashma va shuning uchun erkinlik darajalariga qarama-qarshidir. . Masalan, Ifoda muammosiga o‘xshash kengaytma subtiplash, funksiyani ortiqcha yuklash va parametrik yozishda birlashtirilgan. domenlar.

Mening nazariy pozitsiyam shundaki, bilim mavjud bo'lishi ( "Markaziylashtirish ko'r va yaroqsiz" bo'limiga qarang), Turing-to'liq kompyuter tilida barcha mumkin bo'lgan invariantlarni 100% qamrab oladigan umumiy model hech qachon bo'lmaydi. Bilim mavjud bo'lishi uchun kutilmagan imkoniyatlar juda ko'p, ya'ni tartibsizlik va entropiya doimo ortib borishi kerak. Bu entropik kuch. Potensial kengaytmaning barcha mumkin bo'lgan hisoblarini isbotlash barcha mumkin bo'lgan kengaytmalarni apriori hisoblashdir.

Shuning uchun to'xtash teoremasi mavjud, ya'ni Turing-to'liq dasturlash tilidagi barcha mumkin bo'lgan dastur tugashi yoki tugashi aniq emas. Ba'zi bir maxsus dastur tugashini isbotlash mumkin (barcha imkoniyatlar aniqlangan va hisoblangan). Ammo bu dasturning barcha mumkin bo'lgan kengaytmalari tugashini isbotlash mumkin emas, agar ushbu dasturni kengaytirish imkoniyatlari Turing to'liq bo'lmasa (masalan, bog'liq bo'lgan yozish orqali). Turing-to'liqligi uchun asosiy talab cheklanmagan rekursiya bo'lgani uchun, Gödelning to'liqsizlik teoremalari va Rassell paradoksining kengaytmaga qanday tatbiq etilishini tushunish oson.

Ushbu teoremalarning talqini ularni entropik kuchning umumlashtirilgan kontseptual tushunchasiga kiritadi:

  • Godelning to'liqsizlik teoremalari: barcha arifmetik haqiqatlar isbotlanishi mumkin bo'lgan har qanday rasmiy nazariya mos kelmaydi.
  • Rasselning paradoksi: har bir a'zolik qoidasi to'plamni o'z ichiga olishi mumkin bo'lgan to'plam, har bir a'zoning o'ziga xos turini sanab o'tadi yoki o'zini o'z ichiga oladi. Shunday qilib, to'plamlarni kengaytirib bo'lmaydi yoki ular cheksiz rekursiyadir. Masalan, choynak bo'lmagan hamma narsaning to'plami o'zini o'z ichiga oladi, o'zini o'z ichiga oladi, o'zini o'z ichiga oladi va hokazo. Shunday qilib, qoida (to'plamni o'z ichiga olishi mumkin va) o'ziga xos turlarni sanab o'tmasa (ya'ni, barcha noaniq turlarga ruxsat bersa) va cheksiz kengaytirishga ruxsat bermasa, nomuvofiq hisoblanadi. Bu o'z a'zolari bo'lmagan to'plamlar to'plami. Barcha mumkin bo'lgan kengaytmalar bo'yicha ham izchil va to'liq sanab bo'lmaydigan bu Gödelning to'liqsizlik teoremasidir.
  • Liskovni almashtirish printsipi: umuman olganda, biron bir to'plam boshqasining pastki to'plami bo'ladimi yoki yo'qmi - bu hal qilib bo'lmaydigan muammo, ya'ni merosxo'rlikni umuman hal qilib bo'lmaydi.
  • Linskiyga havola qilish: biror narsa tasvirlangan yoki idrok etilganda, uni hisoblash nima ekanligini hal qilib bo'lmaydi, ya'ni idrok (haqiqat) mutlaq murojaat nuqtasiga ega emas.
  • Kouz teoremasi: hech qanday tashqi mos yozuvlar nuqtasi yo'q, shuning uchun cheksiz tashqi imkoniyatlar uchun har qanday to'siq barbod bo'ladi.
  • Termodinamikaning ikkinchi qonuni: butun olam (yopiq tizim, ya'ni hamma narsa) maksimal tartibsizlikka, ya'ni maksimal mustaqil imkoniyatlarga moyillik.
person Shelby Moore III    schedule 26.11.2011
comment
@Shelyby: Siz juda ko'p narsalarni aralashtirdingiz. Ishlar siz aytgandek chalkash emas. Nazariy da'volaringizning aksariyati "Bilim mavjud bo'lishi uchun kutilmagan imkoniyatlar ko'p bo'ladi, ........." kabi asossiz asoslarga asoslangan VA "umuman olganda, biron bir to'plam boshqasining pastki to'plamimi yoki yo'qmi, bu hal qilib bo'lmaydigan muammodir, ya'ni. meros, odatda, hal qilib bo'lmaydi. Ushbu nuqtalarning har biri uchun alohida blog ochishingiz mumkin. Qanday bo'lmasin, sizning taxminlaringiz va taxminlaringiz juda shubhali. O'zi bilmagan narsalarni ishlatmaslik kerak! - person aknon; 27.12.2013
comment
@aknon Menda blogim bor unda bu masalalarni chuqurroq tushuntirib beradi. Mening cheksiz fazoviy vaqtdagi BO modeli cheklanmagan chastotalardir. Rekursiv induktiv funktsiyaning cheksiz chegarasi bilan ma'lum boshlang'ich qiymati yoki koinduktiv funktsiyaning noma'lum yakuniy qiymati va ma'lum boshlang'ich chegarasi borligi meni chalkashtirib yubormaydi. Rekursiya kiritilgandan keyin nisbiylik muammosi. Shuning uchun Tugallanish cheksiz rekursiyaga teng. - person Shelby Moore III; 16.03.2014
comment
@ShelbyMooreIII Siz juda ko'p yo'nalishlarga borasiz. Bu javob emas. - person Soldalma; 09.12.2016
comment
@Soldalma bu javob. Javob bo'limida buni ko'rmayapsizmi? Sizniki sharh, chunki u sharh bo'limida. - person Shelby Moore III; 23.12.2016
comment
@aknon sizning bema'nilik haqidagi da'volaringizga kelsak, men blog yozdim. va yozma, sizga 2014-yilda javob berganimdan beri. - person Shelby Moore III; 23.12.2016
comment
Skala dunyosi bilan aralashishingiz kabi! - person Ehsan M. Kermani; 28.06.2017

Men har bir javobda to'rtburchaklar va kvadratlarni va LSPni qanday buzishni ko'raman.

LSP ni haqiqiy misol bilan qanday qilib moslashtirish mumkinligini ko'rsatmoqchiman:

<?php

interface Database 
{
    public function selectQuery(string $sql): array;
}

class SQLiteDatabase implements Database
{
    public function selectQuery(string $sql): array
    {
        // sqlite specific code

        return $result;
    }
}

class MySQLDatabase implements Database
{
    public function selectQuery(string $sql): array
    {
        // mysql specific code

        return $result; 
    }
}

Ushbu dizayn LSP ga mos keladi, chunki biz tanlagan dasturdan qat'iy nazar xatti-harakatlar o'zgarishsiz qoladi.

Va ha, siz ushbu konfiguratsiyadagi LSPni bitta oddiy o'zgartirish orqali buzishingiz mumkin:

<?php

interface Database 
{
    public function selectQuery(string $sql): array;
}

class SQLiteDatabase implements Database
{
    public function selectQuery(string $sql): array
    {
        // sqlite specific code

        return $result;
    }
}

class MySQLDatabase implements Database
{
    public function selectQuery(string $sql): array
    {
        // mysql specific code

        return ['result' => $result]; // This violates LSP !
    }
}

Endi kichik turlardan bir xil tarzda foydalanish mumkin emas, chunki ular endi bir xil natijani bermaydilar.

person Steve Chamaillard    schedule 18.02.2018
comment
Agar biz barcha ma'lumotlar bazasi dvigatellari tomonidan qo'llab-quvvatlanadigan SQL quyi to'plamini qo'llab-quvvatlash uchun Database::selectQuery semantikasini cheklab qo'ysak, misol LSPni buzmaydi. Bu deyarli amaliy emas... Ya'ni, misolni tushunish bu erda qo'llanilgan ko'pchilikka qaraganda osonroq. - person Palec; 25.02.2018
comment
Men bu javobni qolganlardan tushunish eng oson deb topdim. - person Malcolm Salvador; 11.02.2019
comment
LSPni ma'lumotlar bazalarida qo'llash amaliymi? Men ko'ramanki, JB operatsiyalarining hammasi bo'lmasa ham, o'ralishi kerak bo'ladi va xatolarga moyil. Yaxshi tomoni shundaki, API SQL va NoSQL bo'lsa ham bir xil bo'lib qoladi. - person Sean W; 23.08.2020

Liskovni buzgan yoki yo'qligini aniqlash uchun nazorat ro'yxati mavjud.

  • Agar siz quyidagi bandlardan birini buzsangiz -› siz Liskovni buzasiz.
  • Agar siz hech qanday qoidani buzmasangiz -› hech narsa xulosa qila olmaysiz.

Tekshirish roʻyxati:

  • Olingan sinfda hech qanday yangi istisnolar kiritilmasligi kerak: Agar sizning asosiy sinfingiz ArgumentNullException-ni tashlagan bo'lsa, quyi sinflaringizga faqat ArgumentNullException turidagi istisnolarni yoki ArgumentNullException-dan olingan har qanday istisnolarni tashlashga ruxsat berilgan. IndexOutOfRangeExceptionni tashlash Liskov qoidasini buzish hisoblanadi.

  • Oldin shartlarni kuchaytirib bo'lmaydi: Sizning asosiy sinfingiz int a'zosi bilan ishlaydi deb faraz qiling. Endi sizning pastki turingiz bu int ijobiy bo'lishini talab qiladi. Bu kuchaytirilgan oldingi shartlar va endi salbiy ints bilan oldin juda yaxshi ishlagan har qanday kod buziladi.

  • Post-shartlarni zaiflashtirib bo'lmaydi: Tasavvur qiling-a, sizning asosiy sinfingiz ma'lumotlar bazasiga barcha ulanishlar qaytarilishidan oldin yopilishi kerak. O'zingizning kichik sinfingizda siz ushbu usulni bekor qildingiz va ulanishni qayta ishlatish uchun ochiq qoldirdingiz. Siz ushbu usulning keyingi shartlarini zaiflashtirdingiz.

  • Invariantlar saqlanishi kerak: Bajarish eng qiyin va og'riqli cheklov. Invariantlar ba'zan asosiy sinfda yashiringan va ularni ochishning yagona yo'li asosiy sinf kodini o'qishdir. Asosan, siz biron bir usulni bekor qilganingizda, bekor qilingan usulingiz bajarilgandan keyin o'zgarmas narsa o'zgarishsiz qolishi kerakligiga ishonch hosil qilishingiz kerak. Men o'ylashim mumkin bo'lgan eng yaxshi narsa bu o'zgarmas cheklovlarni asosiy sinfda qo'llashdir, ammo bu oson bo'lmaydi.

  • Tarix cheklovi: Usulni bekor qilishda sizga asosiy sinfdagi o'zgartirilmaydigan xususiyatni o'zgartirishga ruxsat berilmaydi. Ushbu kodni ko'rib chiqing va siz Ism o'zgarmas deb belgilanganligini ko'rishingiz mumkin (shaxsiy to'plam), lekin SubType uni o'zgartirishga imkon beruvchi yangi usulni taqdim etadi (aks ettirish orqali):

     public class SuperType
     {
         public string Name { get; private set; }
         public SuperType(string name, int age)
         {
             Name = name;
             Age = age;
         }
     }
     public class SubType : SuperType
     {
         public void ChangeName(string newName)
         {
             var propertyType = base.GetType().GetProperty("Name").SetValue(this, newName);
         }
     }
    

Yana 2 ta element mavjud: Usul argumentlarining kontravariatsiyasi va Qaytish turlarining kovariatsiyasi. Lekin C# da bu mumkin emas (men C# dasturchisiman), shuning uchun men ularga ahamiyat bermayman.

person Cù Đức Hiếu    schedule 13.08.2016
comment
Men ham C# dasturchisiman va sizning oxirgi bayonotingiz .Net 4.0 ramkasi bilan Visual Studio 2010 bo'yicha to'g'ri emasligini aytaman. Qaytish turlarining kovariatsiyasi interfeys tomonidan belgilanganidan ko'ra ko'proq olingan qaytish turiga imkon beradi. Misol: IEnumerable‹T› (T - kovariant) IEnumerator‹T› (T - kovariant) IQueryable‹T› (T - kovariant) IGrouping‹TKey, TElement› (TKey va TElement kovariant) IComparer‹T kontravariant) IEqualityComparer‹T› (T ziddiyatli) IComparable‹T› (T ziddiyatli) msdn.microsoft.com/en-us/library/dd233059(v=vs.100).aspx - person LCarter; 05.09.2017
comment
Ajoyib va ​​diqqatli javob (asl savollar qoidalardan ko'ra ko'proq misollar haqida edi). - person Mike; 12.06.2018

Uzoqning qisqasi, keling, to'rtburchaklar to'rtburchaklar va kvadratchalar qoldiraylik, ota-klassni kengaytirishda amaliy misol, siz aniq asosiy API-ni SAQLASH yoki UNNI KENGAYTISH kerak.

Aytaylik, sizda baza ItemsRepository bor.

class ItemsRepository
{
    /**
    * @return int Returns number of deleted rows
    */
    public function delete()
    {
        // perform a delete query
        $numberOfDeletedRows = 10;

        return $numberOfDeletedRows;
    }
}

Va uni kengaytiradigan kichik sinf:

class BadlyExtendedItemsRepository extends ItemsRepository
{
    /**
     * @return void Was suppose to return an INT like parent, but did not, breaks LSP
     */
    public function delete()
    {
        // perform a delete query
        $numberOfDeletedRows = 10;

        // we broke the behaviour of the parent class
        return;
    }
}

Shunda siz Base ItemsRepository API bilan ishlaydigan va unga tayanadigan Mijozga ega bo'lishingiz mumkin.

/**
 * Class ItemsService is a client for public ItemsRepository "API" (the public delete method).
 *
 * Technically, I am able to pass into a constructor a sub-class of the ItemsRepository
 * but if the sub-class won't abide the base class API, the client will get broken.
 */
class ItemsService
{
    /**
     * @var ItemsRepository
     */
    private $itemsRepository;

    /**
     * @param ItemsRepository $itemsRepository
     */
    public function __construct(ItemsRepository $itemsRepository)
    {
        $this->itemsRepository = $itemsRepository;
    }

    /**
     * !!! Notice how this is suppose to return an int. My clients expect it based on the
     * ItemsRepository API in the constructor !!!
     *
     * @return int
     */
    public function delete()
    {
        return $this->itemsRepository->delete();
    }
} 

LSPni almashtirishda ota-ona sinfni quyi sinf bilan API shartnomasini buzganda buziladi.

class ItemsController
{
    /**
     * Valid delete action when using the base class.
     */
    public function validDeleteAction()
    {
        $itemsService = new ItemsService(new ItemsRepository());
        $numberOfDeletedItems = $itemsService->delete();

        // $numberOfDeletedItems is an INT :)
    }

    /**
     * Invalid delete action when using a subclass.
     */
    public function brokenDeleteAction()
    {
        $itemsService = new ItemsService(new BadlyExtendedItemsRepository());
        $numberOfDeletedItems = $itemsService->delete();

        // $numberOfDeletedItems is a NULL :(
    }
}

Siz mening kursimda qo'llab-quvvatlanadigan dasturiy ta'minotni yozish haqida ko'proq bilib olishingiz mumkin: https://www.udemy.com/enterprise-php/

person Lukas Lukac    schedule 28.10.2017
comment
Bu ancha yaxshi misol. Rahmat! - person Kurt Campher; 14.02.2021

LSP - bu to'g'ridan-to'g'ri shartnoma bo'yicha qoida: agar asosiy sinf shartnomani qondirsa, LSP tomonidan olingan sinflar ham ushbu shartnomani qondirishi kerak.

Pseudo-python tilida

class Base:
   def Foo(self, arg): 
       # *... do stuff*

class Derived(Base):
   def Foo(self, arg):
       # *... do stuff*

Agar Foo-ni Derived ob'ektida har safar chaqirganingizda, arg bir xil bo'lsa, asosiy ob'ektda Foo-ga qo'ng'iroq qilish bilan bir xil natijalarni beradi, agar LSP-ni qondiradi.

person Charlie Martin    schedule 08.11.2008
comment
Ammo ... agar siz doimo bir xil xatti-harakatga ega bo'lsangiz, unda olingan sinfga ega bo'lishning nima keragi bor? - person Leonid; 03.07.2012
comment

Bu siz o'ylaganingizdan ancha sodda:

usr->next = group->users;
group->users = usr;
- person Charlie Martin; 04.07.2012
comment
@Charli Martin, amalga oshirishdan ko'ra interfeysga kodlash - men buni qazib oldim. Bu OOP uchun xos emas; Clojure kabi funktsional tillar ham buni targ'ib qiladi. Java yoki C# tillarida ham mavhum sinf va sinf ierarxiyasidan foydalanish o'rniga interfeysdan foydalanish siz taqdim etgan misollar uchun tabiiy bo'ladi deb o'ylayman. Python qattiq yozilmagan va interfeyslarga ega emas, hech bo'lmaganda aniq emas. Mening qiyinligim shundaki, men bir necha yil davomida SOLID ga rioya qilmasdan OOP bilan shug'ullanaman. Endi men unga duch kelganimda, bu cheklovchi va deyarli o'z-o'zidan qarama-qarshi bo'lib tuyuladi. - person Hamish Grubijan; 06.07.2012
comment
Xo'sh, siz orqaga qaytib, Barbaraning asl qog'ozini tekshirishingiz kerak. reports-archive.adm.cs. cmu.edu/anon/1999/CMU-CS-99-156.ps Bu aslida interfeyslar nuqtai nazaridan aytilmagan va bu mantiqiy munosabat bo'lib, har qanday dasturlash tilida mavjud (yoki yo'q) merosning qandaydir shakli. - person Charlie Martin; 07.07.2012
comment
@HamishGrubijan Men sizga Python qattiq yozilmaganligini kim aytdi, bilmayman, lekin ular sizga yolg'on gapirishdi (va agar menga ishonmasangiz, Python tarjimonini ishga tushiring va 2 + "2" ni sinab ko'ring). Balki siz qattiq terilgan bilan statik terilganni chalkashtirasizmi? - person asmeurer; 20.01.2013
comment
@asmeurer Hamish noto'g'ri emas. Kuchli terilgan bu yaxshi aniqlangan atama emas; ba'zan u qandaydir statik turni tekshirishga ega (Hamish ma'nosi), ba'zida turdagi majburlashni amalga oshirmaydi degan ma'noda ishlatiladi (sizning ma'nongiz va odatdagidek faqat "string-to-son" turidagi majburlashning o'ziga xos holatiga nisbatan. ' - Men hech kim C ning zaif terilganligi, chunki siz intsni float bilan ko'paytirishingiz mumkin yoki Python u'hello' ni 'world' bilan birlashtira olasiz, deb bahslashayotganini hech qachon ko'rmaganman) va ba'zan boshqa ko'p narsalardan birini anglatadi. en.wikipedia.org/wiki/Strong_and_weak_typing - person Mark Amery; 27.12.2013
comment
Liskov nuqtai nazaridan, ular boshqacha, chunki ular doimo ishlaydi. Agar til 2 + '2' tilini qo‘llab-quvvatlasa, u hali ham 2 + 'two' tilini qo‘llab-quvvatlamaydi. - person asmeurer; 27.12.2013
comment
G'alati, @MarkAmery, siz bog'lagan wiki maqolasi mening "kuchli terilgan" dan foydalanishimni qo'llab-quvvatlaydi. Odamlar uni noto'g'ri ishlatganliklari ta'rifni noto'g'ri qilmaydi. 1974 yilda Liskov va Zilles kuchli tiplangan tilni shunday ta'rifladilarki, unda ob'ekt chaqiruvchi funksiyadan chaqirilgan funksiyaga o'tkazilganda uning turi chaqirilayotgan funksiyada e'lon qilingan turga mos kelishi kerak. - person Charlie Martin; 27.12.2013
comment
@CharlieMartin, agar javobingizni to'g'ri tushungan bo'lsam, LSP - bu ota-ona sinfining har qanday nusxasini salbiy nojo'ya ta'sirlarsiz uning bolalar sinflaridan birining namunasi bilan almashtirish qobiliyati, to'g'rimi? - person Daniel; 27.10.2018

O'ylaymanki, hamma LSP nima ekanligini texnik jihatdan yoritadi: siz asosan subtip tafsilotlaridan mavhum bo'lishni va supertiplardan xavfsiz foydalanishni xohlaysiz.

Shunday qilib, Liskovning uchta asosiy qoidasi bor:

  1. Imzo qoidasi: subtipdagi har bir supertip operatsiyasining sintaktik tarzda to'g'ri bajarilishi kerak. Biror narsa kompilyator sizni tekshira oladi. Kamroq istisnolardan voz kechish va hech bo'lmaganda supertip usullari kabi foydalanish mumkin bo'lishi haqida bir oz qoida mavjud.

  2. Usullar qoidasi: Ushbu operatsiyalarni amalga oshirish semantik jihatdan to'g'ri.

    • Weaker Preconditions : The subtype functions should take at least what the supertype took as input, if not more.
    • Kuchliroq keyingi shartlar: ular ishlab chiqarilgan supertipli usullarning bir qismini ishlab chiqarishi kerak.
  3. Xususiyatlar qoidasi: Bu individual funktsiya chaqiruvlaridan tashqariga chiqadi.

    • Invariants : Things that are always true must remain true. Eg. a Set's size is never negative.
    • Evolyutsion xususiyatlar : Odatda biror narsa o'zgarmasligi yoki ob'ekt qanday holatda bo'lishi mumkinligi bilan bog'liq. Yoki ob'ekt faqat o'sadi va hech qachon qisqarmaydi, shuning uchun subtip usullari uni yaratmasligi kerak.

Bu xususiyatlarning barchasi saqlanishi kerak va qo'shimcha pastki turdagi funksionallik supertip xususiyatlarini buzmasligi kerak.

Agar ushbu uchta narsaga e'tibor berilsa, siz asosiy narsadan mavhum bo'lgansiz va siz erkin bog'langan kod yozyapsiz.

Manba: Java-da dastur ishlab chiqish - Barbara Liskov

person snagpaul    schedule 18.12.2016

Keling, Java-da tasvirlab beraylik:

class TrasportationDevice
{
   String name;
   String getName() { ... }
   void setName(String n) { ... }

   double speed;
   double getSpeed() { ... }
   void setSpeed(double d) { ... }

   Engine engine;
   Engine getEngine() { ... }
   void setEngine(Engine e) { ... }

   void startEngine() { ... }
}

class Car extends TransportationDevice
{
   @Override
   void startEngine() { ... }
}

Bu erda hech qanday muammo yo'q, to'g'rimi? Avtomobil, albatta, transport vositasidir va bu erda biz o'z super klassining startEngine() usulini bekor qilishini ko'rishimiz mumkin.

Keling, boshqa transport vositasini qo'shamiz:

class Bicycle extends TransportationDevice
{
   @Override
   void startEngine() /*problem!*/
}

Hozir hammasi rejalashtirilganidek bo'lmayapti! Ha, velosiped transport vositasidir, ammo uning dvigateli yo'q, shuning uchun startEngine() usulini amalga oshirib bo'lmaydi.

Bu Liskov almashtirish printsipining buzilishiga olib keladigan muammolardir va ular odatda hech narsa qilmaydigan yoki hatto amalga oshirib bo'lmaydigan usul bilan tan olinishi mumkin.

Ushbu muammolarni hal qilish to'g'ri meros ierarxiyasidir va bizning holatlarimizda biz dvigatelli va dvigatelsiz transport vositalarining sinflarini farqlash orqali muammoni hal qilamiz. Velosiped transport vositasi bo'lsa ham, uning dvigateli yo'q. Ushbu misolda transport qurilmasiga bizning ta'rifimiz noto'g'ri. Uning dvigateli bo'lmasligi kerak.

TransportationDevice sinfimizni quyidagicha refaktor qilishimiz mumkin:

class TrasportationDevice
{
   String name;
   String getName() { ... }
   void setName(String n) { ... }

   double speed;
   double getSpeed() { ... }
   void setSpeed(double d) { ... }
}

Endi biz TransportationDevice-ni motorsiz qurilmalar uchun kengaytirishimiz mumkin.

class DevicesWithoutEngines extends TransportationDevice
{  
   void startMoving() { ... }
}

Va motorli qurilmalar uchun TransportationDevice-ni kengaytiring. Bu erda Dvigatel ob'ektini qo'shish maqsadga muvofiqdir.

class DevicesWithEngines extends TransportationDevice
{  
   Engine engine;
   Engine getEngine() { ... }
   void setEngine(Engine e) { ... }

   void startEngine() { ... }
}

Shunday qilib, bizning Avtomobil sinfimiz Liskov almashtirish printsipiga rioya qilgan holda yanada ixtisoslashgan bo'ladi.

class Car extends DevicesWithEngines
{
   @Override
   void startEngine() { ... }
}

Va bizning velosiped sinfimiz Liskov almashtirish printsipiga mos keladi.

class Bicycle extends DevicesWithoutEngines
{
   @Override
   void startMoving() { ... }
}
person Khaled Qasem    schedule 10.02.2019

Ko'rsatkichlar yoki asosiy sinflarga havolalardan foydalanadigan funksiyalar hosila sinflari ob'ektlarini bilmagan holda ishlata olishi kerak.

Men LSP haqida birinchi marta o'qiganimda, men bu juda qat'iy ma'noda nazarda tutilgan deb o'ylagan edim, asosan uni interfeysni amalga oshirish va turdagi xavfsiz kasting bilan tenglashtirdi. Bu LSP tilning o'zi tomonidan ta'minlangan yoki ta'minlanmaganligini anglatadi. Misol uchun, bu qat'iy ma'noda, ThreeDBoard, albatta, kompilyatorga kelsak, Board o'rnini bosadi.

Kontseptsiya haqida ko'proq o'qib chiqqanimdan so'ng, men LSP odatda undan kengroq talqin qilinishini topdim.

Muxtasar qilib aytganda, mijoz kodi uchun ko'rsatgich orqasidagi ob'ekt ko'rsatgich turi emas, balki hosila turi ekanligini "bilish" nimani anglatadi, bu xavfsizlik turi bilan cheklanmaydi. LSP ga rioya qilish ob'ektlarning haqiqiy xatti-harakatlarini tekshirish orqali ham tekshiriladi. Ya'ni, ob'ekt holati va usul argumentlarining metod chaqiruvlari natijalariga ta'sirini yoki ob'ektdan tashlangan istisnolar turlarini o'rganish.

Yana misolga qaytadigan bo'lsak,nazariy jihatdanThreeDBoard-da kengash usullarini juda yaxshi ishlashi mumkin. Amalda esa, ThreeDBoard qo'shmoqchi bo'lgan funksionallikni buzmasdan, mijoz to'g'ri bajara olmaydigan xatti-harakatlardagi farqlarning oldini olish juda qiyin bo'ladi.

Ushbu bilim bilan LSPga rioya qilishni baholash merosdan ko'ra mavjud funksionallikni kengaytirish uchun qachon mosroq mexanizm ekanligini aniqlashda ajoyib vosita bo'lishi mumkin.

person Chris Ammerman    schedule 11.09.2008

LSP danfoydalanishning muhim misoli dasturiy ta'minotni sinovdan o'tkazishdadir.

Agar menda B ning LSP-mos keladigan kichik sinfi bo'lgan A sinfim bo'lsa, men A testini o'tkazish uchun B test to'plamidan qayta foydalanishim mumkin.

A kichik sinfini to'liq sinab ko'rish uchun men yana bir nechta test holatlarini qo'shishim kerak, lekin hech bo'lmaganda barcha supersinf B test holatlarini qayta ishlatishim mumkin.

Buni tushunishning bir yo'li MakGregor "sinov uchun parallel ierarxiya" deb atagan narsani yaratishdir: Mening ATest sinfim BTest sinfidan meros bo'lib qoladi. Sinov ishining B tipidagi emas, balki A tipidagi ob'ektlar bilan ishlashini ta'minlash uchun in'ektsiyaning qandaydir shakli kerak bo'ladi (oddiy shablon usuli namunasi ishlaydi).

Shuni esda tutingki, barcha kichik sinf ilovalari uchun super-testlar to'plamidan qayta foydalanish, aslida, ushbu kichik sinf ilovalari LSP-mosligini tekshirishning bir usuli hisoblanadi. Shunday qilib, har qanday kichik sinf kontekstida supersinf test to'plaminiishlatishkerakligi haqida ham bahslashish mumkin.

Shuningdek, Stackoverflow savoliga "Interfeys amalga oshirilishini sinab ko‘rish uchun qayta foydalanish mumkin bo‘lgan bir qator testlarni amalga oshira olamanmi?"ga qarang.

person avandeursen    schedule 25.03.2013

Juda oddiy jumlada aytishimiz mumkin:

Bolalar sinfi o'zining asosiy sinf xususiyatlarini buzmasligi kerak. U bunga qodir bo'lishi kerak. Aytishimiz mumkinki, bu subtyping bilan bir xil.

person Alireza Rahmani khalili    schedule 16.08.2017

Liskov almashtirish printsipi

  • Bekor qilingan usul bo'sh qolmasligi kerak
  • Bekor qilingan usul xatoga yo'l qo'ymasligi kerak
  • Asosiy sinf yoki interfeys harakati, olingan sinf xatti-harakatlari tufayli o'zgartirish (qayta ishlash) uchun ketmasligi kerak.
person Rahamath    schedule 19.08.2019

LSP ning ushbu formulasi juda kuchli:

Agar S tipidagi har bir o1 ob'ekti uchun T tipidagi o2 ob'ekti mavjud bo'lsa, T bilan belgilangan barcha P dasturlar uchun o2 o'rniga o1 o'rniga P ning xatti-harakati o'zgarmaydi, u holda S T ning kichik turidir.

Bu, asosan, S bu T bilan bir xil narsaning boshqa, to'liq qamrab olingan amalga oshirilishini anglatadi. Va men dadil bo'lishim va ishlash P xatti-harakatining bir qismi ekanligiga qaror qilishim mumkin ...

Shunday qilib, asosan, kechikishning har qanday ishlatilishi LSPni buzadi. Bir turdagi ob'ektni boshqa turdagi ob'ektga almashtirganimizda, boshqa xatti-harakatlarga ega bo'lish OO'ning butun maqsadidir!

wikipedia tomonidan keltirilgan formula yaxshiroq, chunki xususiyat kontekstga bog'liq va barchani o'z ichiga olmaydi. dasturning xatti-harakati.

person Damien Pollet    schedule 03.04.2009
comment
Ha, bu formula Barbara Liskovniki. Barbara Liskov, "Ma'lumotlarning abstraktsiyasi va ierarxiyasi", SIGPLAN xabarlari, 23,5 (May, 1988). Bu unchalik kuchli emas, u juda to'g'ri va siz o'ylagandek ma'noga ega emas. U kuchli, lekin kerakli kuchga ega. - person DrPizza; 30.11.2009
comment
Keyin, haqiqiy hayotda juda kam kichik turlar mavjud :) - person Damien Pollet; 09.12.2009
comment
Xulq-atvorning o'zgarmasligi pastki tur sizga aynan bir xil aniq natijalar qiymatini berishi degani emas. Bu pastki turning xatti-harakati asosiy turda kutilgan narsaga mos kelishini anglatadi. Misol: Shaklning asosiy turi draw() usuliga ega bo'lishi mumkin va bu usul shaklni ko'rsatishini talab qiladi. Shaklning ikkita kichik turi (masalan, Kvadrat va Aylana) draw() usulini qo'llaydi va natijalar boshqacha ko'rinadi. Ammo xatti-harakatlar (shaklni ko'rsatish) Shaklning belgilangan xatti-harakatlariga mos kelsa, Kvadrat va Aylana LSP ga muvofiq Shaklning pastki turlari bo'ladi. - person SteveT; 11.10.2012

Liskovning almashtirish printsipi (LSP)

Biz har doim dastur modulini loyihalashtiramiz va ba'zi sinf ierarxiyalarini yaratamiz. Keyin biz ba'zi hosila sinflarni yaratib, ba'zi sinflarni kengaytiramiz.

Biz yangi olingan sinflar eski sinflarning funksiyalarini almashtirmasdan kengaytirilishiga ishonch hosil qilishimiz kerak. Aks holda, yangi sinflar mavjud dastur modullarida foydalanilganda istalmagan effektlarni keltirib chiqarishi mumkin.

Liskovning almashtirish printsipida aytilishicha, agar dastur moduli Base sinfidan foydalansa, u holda Base sinfiga havolani dastur modulining funksionalligiga ta'sir qilmasdan Derived sinfiga almashtirish mumkin.

Misol:

Quyida Liskovning almashtirish printsipi buzilgan klassik misol keltirilgan. Misolda 2 ta sinfdan foydalanilgan: To'rtburchak va Kvadrat. Faraz qilaylik, Rectangle obyekti ilovaning biror joyidan foydalanilgan. Biz ilovani kengaytiramiz va Square sinfini qo'shamiz. Kvadrat sinf ba'zi shartlarga asoslanib zavod namunasi bilan qaytariladi va biz qaysi turdagi ob'ekt qaytarilishini aniq bilmaymiz. Lekin biz bu to'rtburchak ekanligini bilamiz. Biz to'rtburchak ob'ektni olamiz, kengligi 5 ga va balandlikni 10 ga o'rnatamiz va maydonni olamiz. Kengligi 5 va balandligi 10 bo'lgan to'rtburchak uchun maydon 50 bo'lishi kerak. Buning o'rniga natija 100 bo'ladi.

    // Violation of Likov's Substitution Principle
class Rectangle {
    protected int m_width;
    protected int m_height;

    public void setWidth(int width) {
        m_width = width;
    }

    public void setHeight(int height) {
        m_height = height;
    }

    public int getWidth() {
        return m_width;
    }

    public int getHeight() {
        return m_height;
    }

    public int getArea() {
        return m_width * m_height;
    }
}

class Square extends Rectangle {
    public void setWidth(int width) {
        m_width = width;
        m_height = width;
    }

    public void setHeight(int height) {
        m_width = height;
        m_height = height;
    }

}

class LspTest {
    private static Rectangle getNewRectangle() {
        // it can be an object returned by some factory ...
        return new Square();
    }

    public static void main(String args[]) {
        Rectangle r = LspTest.getNewRectangle();

        r.setWidth(5);
        r.setHeight(10);
        // user knows that r it's a rectangle.
        // It assumes that he's able to set the width and height as for the base
        // class

        System.out.println(r.getArea());
        // now he's surprised to see that the area is 100 instead of 50.
    }
}

Xulosa:

Bu tamoyil faqat Ochiq yopish printsipining kengaytmasi bo'lib, biz yangi olingan sinflar o'z xatti-harakatlarini o'zgartirmasdan asosiy sinflarni kengaytirayotganiga ishonch hosil qilishimiz kerakligini anglatadi.

Shuningdek qarang: Ochiq yopish printsipi

Yaxshiroq tuzilish uchun shunga o'xshash tushunchalar: Konfiguratsiya bo'yicha konventsiya

person GauRang Omar    schedule 21.05.2018

LSP oddiy tilda bir xil ob'ektlarni superklass hech narsani buzmasdan bir-biri bilanalmashtirishga ega bo'lishi kerak.

Misol uchun, agar bizda Animal sinfidan olingan Cat va Dog sinflari bo'lsa, Animal sinfidan foydalanadigan har qanday funktsiyalar Cat yoki Dog dan foydalanishi va odatdagidek harakat qilishi kerak.

person johannesMatevosyan    schedule 24.01.2020

Ushbu tamoyil 1987 yildaBarbara Liskov tomonidan kiritilgan va supersinf va uning kichik turlarining xatti-harakatlariga e'tibor qaratish orqali Ochiq-yopiq printsipni kengaytiradi.

Uni buzish oqibatlarini hisobga olsak, uning ahamiyati ayon bo'ladi. Quyidagi sinfdan foydalanadigan dasturni ko'rib chiqing.

public class Rectangle 
{ 
  private double width;

  private double height; 

  public double Width 
  { 
    get 
    { 
      return width; 
    } 
    set 
    { 
      width = value; 
    }
  } 

  public double Height 
  { 
    get 
    { 
      return height; 
    } 
    set 
    { 
      height = value; 
    } 
  } 
}

Tasavvur qiling-a, bir kun mijoz to'rtburchaklar bilan bir qatorda kvadratlarni ham manipulyatsiya qilish qobiliyatini talab qiladi. Kvadrat to'rtburchak bo'lgani uchun kvadrat sinfi Rectangle sinfidan olinishi kerak.

public class Square : Rectangle
{
} 

Biroq, bu bilan biz ikkita muammoga duch kelamiz:

Kvadrat to'rtburchakdan meros qilib olingan balandlik va kenglik o'zgaruvchilariga muhtoj emas va agar biz yuz minglab kvadrat ob'ektlarni yaratishimiz kerak bo'lsa, bu xotirada sezilarli chiqindilarni keltirib chiqarishi mumkin. To'g'ri to'rtburchakdan meros qilib olingan kenglik va balandlik o'rnatuvchisi xususiyatlari kvadrat uchun mos emas, chunki kvadratning kengligi va balandligi bir xil. Ikkala balandlik va kenglikni bir xil qiymatga o'rnatish uchun biz ikkita yangi xususiyatni quyidagicha yaratishimiz mumkin:

public class Square : Rectangle
{
  public double SetWidth 
  { 
    set 
    { 
      base.Width = value; 
      base.Height = value; 
    } 
  } 

  public double SetHeight 
  { 
    set 
    { 
      base.Height = value; 
      base.Width = value; 
    } 
  } 
}

Endi, kimdir kvadrat ob'ektning kengligini o'rnatsa, uning balandligi mos ravishda o'zgaradi va aksincha.

Square s = new Square(); 
s.SetWidth(1); // Sets width and height to 1. 
s.SetHeight(2); // sets width and height to 2. 

Keling, oldinga siljiymiz va ushbu boshqa funktsiyani ko'rib chiqamiz:

public void A(Rectangle r) 
{ 
  r.SetWidth(32); // calls Rectangle.SetWidth 
} 

Agar biz kvadrat ob'ektga havolani ushbu funktsiyaga o'tkazsak, biz LSPni buzgan bo'lamiz, chunki funktsiya uning argumentlarining hosilalari uchun ishlamaydi. Kenglik va balandlik xususiyatlari polimorf emas, chunki ular to'rtburchakda virtual deb e'lon qilinmaydi (kvadrat ob'ekt buziladi, chunki balandlik o'zgartirilmaydi).

Biroq, sozlagich xususiyatlarini virtual deb e'lon qilish orqali biz yana bir qoidabuzarlikka, OCPga duch kelamiz. Darhaqiqat, olingan sinf kvadratining yaratilishi asosiy sinf to'rtburchagida o'zgarishlarga olib keladi.

person Ivan Porta    schedule 02.03.2020
comment
A() usulida siz r.Width = 32; ni nazarda tutdingiz deb o'ylayman, chunki Rectangle da SetWidth() usuli yo'q. - person wired_in; 13.10.2020

Ba'zi qo'shimchalar:
Nima uchun hech kim Invariant , oldingi shartlar va olingan sinflar tomonidan bajarilishi kerak bo'lgan asosiy sinfning post shartlari haqida yozmaganiga hayronman. Olingan D sinfi B asosiy sinfiga to'liq mos kelishi uchun D sinfi ma'lum shartlarga bo'ysunishi kerak:

  • Asosiy sinfning in-variantlari olingan sinf tomonidan saqlanishi kerak
  • Asosiy sinfning oldingi shartlari olingan sinf tomonidan mustahkamlanmasligi kerak
  • Asosiy sinfning keyingi shartlari olingan sinf tomonidan zaiflashmasligi kerak.

Shunday qilib, olingan asosiy sinf tomonidan qo'yilgan yuqoridagi uchta shartdan xabardor bo'lishi kerak. Demak, subtiplash qoidalari oldindan hal qilinadi. Bu shuni anglatadiki, "IS A" munosabatlari faqat kichik turdagi ma'lum qoidalarga bo'ysunganda bo'ysunadi. Invariantlar, oldingi shartlar va keyingi shartlar ko'rinishidagi ushbu qoidalar rasmiy "dizayn shartnomasi'.

Bu haqda keyingi muhokamalar mening blogimda mavjud: Liskov almashtirish printsipi

person aknon    schedule 27.12.2013

Kvadrat - kengligi balandlikka teng bo'lgan to'rtburchak. Agar kvadrat kenglik va balandlik uchun ikki xil o'lchamni o'rnatsa, u kvadrat invariantini buzadi. Bu yon ta'sirlarni kiritish orqali ishlaydi. Ammo agar to'rtburchakda 0 ‹ balandlik va 0 ‹ kenglik sharti bilan belgilangan o'lcham (balandlik, kenglik) bo'lsa. Olingan subtip usuli balandligi == kenglikni talab qiladi; kuchliroq shart (va bu lspni buzadi). Bu shuni ko'rsatadiki, kvadrat to'rtburchak bo'lsa-da, u haqiqiy kichik tur emas, chunki old shart mustahkamlangan. Atrofdagi ish (umuman yomon narsa) yon ta'sirga olib keladi va bu post holatini zaiflashtiradi (bu lspni buzadi). Bazadagi setWidth post sharti 0 ‹ kengligiga ega. Olingan uni balandligi == kengligi bilan zaiflashtiradi.

Shuning uchun o'lchami o'zgartiriladigan kvadrat o'lchami o'zgartiriladigan to'rtburchak emas.

person Wouter    schedule 27.07.2015

Kengashlar qatori nuqtai nazaridan ThreeDBoardni amalga oshirish foydali bo'ladimi?

Ehtimol, siz ThreeDBoard bo'laklarini turli tekisliklarda taxta sifatida ko'rib chiqishni xohlashingiz mumkin. Bunday holda siz bir nechta ilovalarga ruxsat berish uchun Kengash uchun interfeysni (yoki mavhum sinfni) abstrakt qilishni xohlashingiz mumkin.

Tashqi interfeys nuqtai nazaridan siz TwoDBoard va ThreeDBoard uchun Board interfeysini hisobga olishingiz mumkin (yuqoridagi usullardan hech biri mos kelmasa ham).

person Tom Hawtin - tackline    schedule 11.09.2008
comment
Menimcha, misol ThreeDBoard kontekstida kengashdan meros olish mantiqiy emasligini va barcha usul imzolari Z o'qi bilan ma'nosiz ekanligini ko'rsatish uchundir. - person NotMyself; 11.09.2008

LSP uchun men hozirgacha aniqlagan eng aniq tushuntirish "Liskov almashtirish printsipi shuni ko'rsatadiki, olingan sinf ob'ekti tizimda hech qanday xatolikka yo'l qo'ymasdan yoki asosiy sinfning xatti-harakatlarini o'zgartirmasdan asosiy sinf ob'ektini almashtirishi kerak. " dan bu yerda. Maqolada LSPni buzish va uni tuzatish uchun kod misoli keltirilgan.

person Prasa    schedule 03.05.2016
comment
Iltimos, stackoverflow-da kod misollarini keltiring. - person sebenalern; 03.05.2016

Aytaylik, biz kodimizda to'rtburchakdan foydalanamiz

r = new Rectangle();
// ...
r.setDimensions(1,2);
r.fill(colors.red());
canvas.draw(r);

Geometriya darsimizda biz kvadrat to'rtburchakning alohida turi ekanligini bilib oldik, chunki uning kengligi balandligi bilan bir xil uzunlikda. Keling, ushbu ma'lumotlarga asoslanib, Square sinfini ham yarataylik:

class Square extends Rectangle {
    setDimensions(width, height){
        assert(width == height);
        super.setDimensions(width, height);
    }
} 

Agar biz birinchi kodimizdagi Rectangle ni Square bilan almashtirsak, u buziladi:

r = new Square();
// ...
r.setDimensions(1,2); // assertion width == height failed
r.fill(colors.red());
canvas.draw(r);

Buning sababi, Square ning Rectangle sinfida bizda mavjud bo'lmagan yangi old sharti bor: width == height. LSPga ko'ra Rectangle misollari Rectangle pastki sinf misollari bilan almashtirilishi kerak. Buning sababi shundaki, bu misollar Rectangle misollar uchun turdagi tekshiruvdan o'tadi va shuning uchun ular sizning kodingizda kutilmagan xatolarga olib keladi.

Bu "bir kichik turda old shartlarni kuchaytirib bo'lmaydi" qismiga misol bo'ldi. >wiki-maqola. Xulosa qilib aytadigan bo'lsak, LSPni buzish, ehtimol bir nuqtada kodingizda xatolarga olib kelishi mumkin.

person inf3rno    schedule 09.10.2017

LSPning ta'kidlashicha, "Ob'ektlar o'zlarining kichik turlari bilan almashtirilishi kerak". Boshqa tomondan, bu printsipga ishora qiladi

Bolalar sinflari hech qachon ota-onalar sinfining ta'riflarini buzmasligi kerak.

va quyidagi misol LSPni yaxshiroq tushunishga yordam beradi.

LSPsiz:

public interface CustomerLayout{

    public void render();
}


public FreeCustomer implements CustomerLayout {
     ...
    @Override
    public void render(){
        //code
    }
}


public PremiumCustomer implements CustomerLayout{
    ...
    @Override
    public void render(){
        if(!hasSeenAd)
            return; //it isn`t rendered in this case
        //code
    }
}

public void renderView(CustomerLayout layout){
    layout.render();
}

LSP tomonidan tuzatish:

public interface CustomerLayout{
    public void render();
}


public FreeCustomer implements CustomerLayout {
     ...
    @Override
    public void render(){
        //code
    }
}


public PremiumCustomer implements CustomerLayout{
    ...
    @Override
    public void render(){
        if(!hasSeenAd)
            showAd();//it has a specific behavior based on its requirement
        //code
    }
}

public void renderView(CustomerLayout layout){
    layout.render();
}
person Zahra.HY    schedule 06.04.2019

Men sizga maqolani o'qishni taklif qilaman: Liskov almashtirish printsipini buzish (LSP).

U erda siz Liskov almashtirish printsipi nima ekanligini tushuntirishni, uni allaqachon buzgan yoki yo'qligini taxmin qilishga yordam beradigan umumiy maslahatlarni va sinf ierarxiyasini yanada xavfsizroq qilishga yordam beradigan yondashuv namunasini topishingiz mumkin.

person Ryszard Dżegan    schedule 09.09.2013

LISKOV ALMASH PRINCIPI (Mark Seemann kitobidan) biz mijoz yoki amalga oshirishni buzmasdan interfeysning bir ilovasini boshqasi bilan almashtirishimiz kerakligini aytadi. Aynan shu printsip kelajakda yuzaga keladigan talablarni hal qilishga imkon beradi, hatto imkonimiz bo'lsa ham. Bugun ularni oldindan ko'ra olmayman.

Agar kompyuterni devordan uzib qo'ysak (Implementation), na devor rozetkasi (Interfeys) ham, na kompyuter (Mijoz) buzilmaydi (aslida, agar u noutbuk bo'lsa, u hatto ma'lum vaqt davomida batareyasi bilan ham ishlashi mumkin) . Biroq, dasturiy ta'minot bilan mijoz ko'pincha xizmat mavjudligini kutadi. Agar xizmat o'chirilgan bo'lsa, biz NullReferenceException olamiz. Ushbu turdagi vaziyatni hal qilish uchun biz "hech narsa" qilmaydigan interfeysni amalga oshirishimiz mumkin. Bu Null Object[4] deb nomlanuvchi dizayn naqshidir va u taxminan kompyuterni devordan uzib qo'yishga mos keladi. Biz bo'sh ulanishdan foydalanayotganimiz sababli, biz haqiqiy dasturni muammo tug'dirmasdan hech narsa qilmaydigan narsa bilan almashtirishimiz mumkin.

person Raghu Reddy Muttana    schedule 12.08.2016

Likovning almashtirish printsipida aytilishicha, agar dastur moduli Base sinfdan foydalanayotgan bo'lsa, u holda Base sinfiga havola dastur modulining funksionalligiga ta'sir qilmasdan Derived sinfiga almashtirilishi mumkin.

Maqsad - Olingan turlar ularning asosiy turlarini to'liq almashtira olishi kerak.

Misol - Java-da ko-variant qaytish turlari.

person Ishan Aggarwal    schedule 23.09.2017

Mana ushbu postdan parcha. narsalarni yaxshi tushuntiradi:

[...] Ba'zi tamoyillarni tushunish uchun, qachon buzilganligini tushunish muhimdir. Men hozir shunday qilaman.

Ushbu tamoyilning buzilishi nimani anglatadi? Bu ob'ekt interfeys bilan ifodalangan mavhumlik bilan yuklangan shartnomani bajarmasligini anglatadi. Boshqacha qilib aytganda, bu sizning abstraksiyalaringizni noto'g'ri aniqlaganingizni anglatadi.

Quyidagi misolni ko'rib chiqing:

interface Account
{
    /**
     * Withdraw $money amount from this account.
     *
     * @param Money $money
     * @return mixed
     */
    public function withdraw(Money $money);
}
class DefaultAccount implements Account
{
    private $balance;
    public function withdraw(Money $money)
    {
        if (!$this->enoughMoney($money)) {
            return;
        }
        $this->balance->subtract($money);
    }
}

Bu LSPni buzishmi? Ha. Buning sababi, hisob shartnomasida hisob yechib olinishi haqida aytilgan, ammo bu har doim ham shunday emas. Xo'sh, uni tuzatish uchun nima qilishim kerak? Men faqat shartnomani o'zgartiraman:

interface Account
{
    /**
     * Withdraw $money amount from this account if its balance is enough.
     * Otherwise do nothing.
     *
     * @param Money $money
     * @return mixed
     */
    public function withdraw(Money $money);
}

Voilà, endi shartnoma qanoatlantirildi.

Ushbu nozik qoidabuzarlik ko'pincha mijozga qo'llaniladigan aniq ob'ektlar orasidagi farqni aytib berish qobiliyatiga ega bo'ladi. Masalan, birinchi Hisob shartnomasini hisobga olsak, u quyidagicha ko'rinishi mumkin:

class Client
{
    public function go(Account $account, Money $money)
    {
        if ($account instanceof DefaultAccount && !$account->hasEnoughMoney($money)) {
            return;
        }
        $account->withdraw($money);
    }
}

Va bu avtomatik ravishda ochiq-yopiq tamoyilni buzadi [ya'ni, pulni yechib olish talabi uchun. Chunki shartnomani buzgan ob'ektda pul yetarli bo'lmasa nima bo'lishini hech qachon bilmaysiz. Ehtimol, u hech narsa qaytarmaydi, ehtimol istisno tashlanadi. Shunday qilib, siz hasEnoughMoney() yoki interfeysning bir qismi emasligini tekshirishingiz kerak. Shunday qilib, bu majburiy beton sinfga bog'liq tekshiruv OCP buzilishidir].

Bu nuqta, shuningdek, LSP buzilishi haqida tez-tez duch keladigan noto'g'ri tushunchaga ham tegishli. Unda aytilishicha, "agar ota-onaning xatti-harakati bolada o'zgargan bo'lsa, bu LSPni buzadi". Biroq, bunday emas - agar bola ota-onasining shartnomasini buzmasa.

person Vadim Samokhin    schedule 12.08.2018

Unda aytilishicha, agar C E ning kichik turi bo'lsa, u holda E dasturning harakatini o'zgartirmasdan yoki buzmasdan C tipidagi ob'ektlar bilan almashtirilishi mumkin. Oddiy so'zlar bilan aytganda, olingan sinflar o'zlarining ota-onalari o'rnini bosadigan bo'lishi kerak. Misol uchun, agarFermerning o'g'lidehqon bo'lsa, u otasining o'rnida ishlashi mumkin, lekinFermerning o'g'likriketchi bo'lsa, u o'z o'rnida ishlay olmaydi. ota.

Qoidabuzarlik misoli:

public class Plane{

  public void startEngine(){}      

}        
public class FighterJet extends Plane{}
    
public class PaperPlane extends Plane{}

Berilgan misolda FighterPlane va PaperPlane sinflari startEngine() usulini o'z ichiga olgan Plane sinfini kengaytiradi. Shunday qilib, FighterPlane dvigatelni ishga tushirishi aniq, lekin PaperPlane ishlay olmaydi, shuning uchun u LSP ni buzadi.

PaperPlane klassi Plane sinfini kengaytirsa ham va uning o'rnini almashtirishi kerak, lekin Plane namunasi almashtirilishi mumkin bo'lgan mos ob'ekt emas, chunki qog'oz samolyot dvigatelni ishga tushira olmaydi, chunki unda yo'q. Shunday qilib, yaxshi misol bo'ladi,

Hurmatli misol:

public class Plane{ 
} 
public class RealPlane{

  public void startEngine(){} 

}
public class FighterJet extends RealPlane{} 
public class PaperPlane extends Plane{}
person Sarmad Sohail    schedule 22.11.2020

[SOLID]

Wiki Liskov almashtirish printsipi (LSP)

Old shartlarni kichik turda kuchaytirib bo'lmaydi.
Quyi turda keyingi shartlarni zaiflashtirib bo'lmaydi.
Super tipdagi invariantlar quyi turda saqlanishi kerak.

* Old shart va keyingi shartlar function (method) types[Swift funktsiyasi turi. Swift funktsiyasi va usuli]

//C1 <- C2 <- C3

class C1 {}
class C2: C1 {}
class C3: C2 {}
  • Old shartlar (masalan, parameter type funktsiyasi) bir xil yoki zaifroq bo'lishi mumkin. (-› C1 ga intiladi)

  • Keyingi shartlar (masalan, returned type funktsiyasi) bir xil yoki kuchliroq bo'lishi mumkin (-› C3 uchun harakat qiladi)

  • Super turdagi o'zgarmas o'zgaruvchi[Haqida] o'zgarmas bo'lishi kerak

Tezkor

class A {
    func foo(a: C2) -> C2 {
        return C2()
    }
}

class B: A {
    override func foo(a: C1) -> C3 {
        return C3()
    }
}

Java

class A {
    public C2 foo(C2 a) {
        return new C2();
    }
}

class B extends A {

    @Override
    public C3 foo(C2 a) { //You are available pass only C2 as parameter
        return new C3();
    }
}

Subtiplash

  • Sybtype qo'ng'iroq qiluvchidan supertipdan ko'proq narsani talab qilmasligi kerak
  • Sybtype qo'ng'iroq qiluvchiga supertipdan kamroq ta'sir qilmasligi kerak

Argument turlarining kontravariatsiyasi va qaytish turining kovariatsiyasi.

  1. Subtipdagi metod argumentlarining kontravariatsiyasi.
  2. Subtipdagi qaytish turlarining kovariatsiyasi.
  3. Hech qanday yangi istisnolar kichik turdagi usullar bilan o'tkazilmasligi kerak, bundan mustasno, bu istisnolarning o'zi supertip usullari bilan chiqarilgan istisnolarning kichik turlari bo'lgan hollar bundan mustasno.

[Variant, kovariatsiya, ziddiyat]

person yoAlex5    schedule 11.11.2020

Keling, sinab ko'ring, interfeysni ko'rib chiqaylik:

interface Planet{
}

Bu sinf tomonidan amalga oshiriladi:

class Earth implements Planet {
    public $radius;
    public function construct($radius) {
        $this->radius = $radius;
    }
}

Siz Yerdan quyidagi tarzda foydalanasiz:

$planet = new Earth(6371);
$calc = new SurfaceAreaCalculator($planet);
$calc->output();

Endi Yerni kengaytiradigan yana bir sinfni ko'rib chiqing:

class LiveablePlanet extends Earth{
   public function color(){
   }
}

Endi LSPga ko'ra, siz Yer o'rnida LiveablePlanet-dan foydalanishingiz kerak va u tizimingizni buzmasligi kerak. Kabi:

$planet = new LiveablePlanet(6371);  // Earlier we were using Earth here
$calc = new SurfaceAreaCalculator($planet);
$calc->output();

Misollar bu yerdan olingan

person prady00    schedule 26.04.2019
comment
Yomon misol. Earth plant ning misolidir, nega u undan olingan? - person zar; 03.05.2019