LSP: mohiyati, Barbara Liskovning o'rniga qo'yish printsipi dasturlashda

Muallif: IT Sectr Nashr etilgan: 2026-05-12 O'qish vaqti: 9 daq

LSP (Liskov Substitution Principle) — SOLIDning uchinchi printsipi bo'lib, ob'yektga yo'naltirilgan dasturlashda to'g'ri meros olish shartlarini belgilaydi. Printsip Barbara Liskov tomonidan 1987-yilda ishlab chiqilgan va quyidagicha rasmiylashtirilgan: agar S T ning kichik turi bo'lsa, u holda T ob'yektlari dastur xususiyatlarini o'zgartirmasdan S ob'yektlari bilan almashtirilishi mumkin. Robert Martinning Clean Architecture (2017) kitobida ta'kidlanganidek, o'rniga qo'yish printsipi kichik sinf asosiy sinf kontraktini zaiflashtirmasligini talab qiladi.

Asosiy ma'lumotlar

  • LSP — Liskov o'rniga qo'yish printsipi, SOLIDning uchinchi printsipi, to'g'ri meros olish haqida
  • Kichik sinf asosiy sinf kontraktini saqlashi kerak — old shartlar va keyingi shartlar
  • LSP buzilishi kvadrat va to'rtburchak muammosida va tashlanadigan istisnolarda namoyon bo'ladi
  • Kompozitsiya ko'pincha LSPga rioya qilish uchun merosdan afzal
  • Kontrakt bo'yicha dizayn (Design by Contract) — LSPni tekshirishning rasmiy usuli

LSP (Liskov Substitution Principle) nima?

LSP (Liskov Substitution Principle) — Barbara Liskov tomonidan 1987-yilda OOPSLA konferensiyasida ishlab chiqilgan o'rniga qo'yish printsipi. Rasmiy ta'rif: q(x) T turidagi x ob'yektlarining isbotlanadigan xususiyati bo'lsin. U holda q(y) S turidagi y ob'yektlari uchun isbotlanadigan bo'lishi kerak, bu yerda S T ning kichik turi. Oddiy qilib aytganda: kichik sinf ob'yektlari shunday harakat qilishi kerakki, asosiy sinf bilan ishlaydigan kod kichik sinf bilan ham to'g'ri ishlashda davom etsin.

Amalda LSP shuni anglatadiki, kichik sinf asosiy sinf kontraktini buzmasligi kerak. Kontrakt old shartlarni (metodni chaqirish uchun nima talab qilinadi), keyingi shartlarni (chaqiruvdan keyin nima kafolatlanadi) va invariantlarni (ob'yekt hayoti davomida saqlanadigan shartlar) o'z ichiga oladi. Kichik sinf old shartlarni kuchaytirishi yoki keyingi shartlarni zaiflashtirishi mumkin — bu LSPning buzilishi.

LSP buzilishining klassik namunasi — to'rtburchakdan meros oladigan kvadrat. To'rtburchakda setWidth metodi kenglikni o'rnatadi, kvadratda esa — ham kenglikni, ham balandlikni. To'rtburchak harakatini kutayotgan mijoz (bir tomonning o'zgarishi ikkinchisiga ta'sir qilmaydi) kutilmagan natija oladi. Kvadrat to'rtburchakning to'g'ri kichik turi emas.

LSPning rasmiy shartlari

LSP to'g'ri meros olish uchun uchta shart belgilaydi: kichik sinfning old shartlari asosiy sinfning old shartlaridan kuchliroq bo'lishi mumkin emas (kichik sinf ko'proq talab qilmaydi), kichik sinfning keyingi shartlari asosiy sinfning keyingi shartlaridan kuchsizroq bo'lishi mumkin emas (kichik sinf kam kafolat bermaydi), asosiy sinfning invariantlari kichik sinfda saqlanishi kerak. Bu shartlar Bertran Meyerning kontrakt bo'yicha dizayn qoidasi sifatida tanilgan.

Agar kamida bitta shart buzilsa — polimorfizmdan foydalanadigan kod noto'g'ri ishlashi mumkin. Kompilyator semantik kontraktlarni emas, faqat sintaktiklarni tekshiradi. Shuning uchun LSP statik tiplash emas, arxitektura intizomi masalasidir.

Liskov o'rniga qo'yish printsipi qanday ishlaydi

LSP mexanizmi turlarning xatti-harakatlar muvofiqligiga asoslanadi. Agar S sinfi T sinfidan meros olsa, mijoz kodi T kutilgan har joyda S dan foydalana olishi kerak, o'z xatti-harakatini o'zgartirmasdan. Bu nafaqat metod imzolarini, balki ularning semantikasini ham o'z ichiga oladi.

LSP kichik sinfga yangi xatti-harakat qo'shishni taqiqlamaydi. Asosiy sinf uchun yozilgan kodning kutishlarini buzish taqiqlanadi. Agar asosiy sinf save metodi istisno tashlamasligiga kafolat bersa, kichik sinf ularni tashlamasligi kerak. Agar asosiy sinf manfiy bo'lmagan qiymat qaytarsa, kichik sinf manfiy qiymat qaytarmasligi kerak.

Haqiqiy loyihalarda LSP ko'pincha kichik sinf metodlariga shartli mantiq qo'shish orqali buziladi: «agar shart — istisno tashla», «agar shart — null qaytar». Har bir bunday «kutilmagan hodisa» polimorfizmni buzadi va mijoz kodini chaqiruvdan oldin ob'yekt turini tekshirishga majbur qiladi — bu ob'yektga yo'naltirilgan dizayn g'oyasiga ziddir.

Mobil loyihalarda tipik LSP buzilishi asosiy ViewModel yaratishda yuz beradi. Agar BaseViewModel onCleared metodi barcha resurslarni bo'shatishiga kafolat bersa, kichik sinf esa bu metodni bo'sh qilib qayta yozsa — onClearedning polimorf chaqiruvi orqali resurslarni bo'shatishga tayanadigan har qanday kod noto'g'ri ishlaydi. LSP kichik sinf yoki super.onCleared() ni chaqirishini yoki o'zi xuddi shu ishni bajarishini talab qiladi. LifecycleObserver orqali kompozitsiya — hayot sikli boshqaruvida LSP buzilishini istisno qiladigan alternativ.

LSP buzilishining kodlardagi belgilari

Asosiy ko'rsatkichlar LSP buzilishiga quyidagilar kiradi: metodni chaqirishdan oldin ob'yekt turini instanceof yoki is orqali tekshirish, metodlarning bo'sh implementatsiyalari (stublar), NotImplementedError yoki UnsupportedOperationException istisnosini tashlash, qiymat o'rniga null qaytarish. Ushbu naqshlarning har biri kichik sinfning to'g'ri kichik tur emasligini ko'rsatadi.

Yana bir keng tarqalgan belgi — «dir» (is-a) munosabatini modellashtirish uchun emas, balki kodni qayta ishlatish maqsadida meros olish. Bird sinfi fly() metodiga ega. Penguin sinfi Bird dan meros oladi va fly() ni bo'sh yoki istisno tashlaydigan qilib qayta yozadi. Bu LSP buzilishi: pingvin qushning to'g'ri kichik turi emas.

Mobil dasturlashda LSP stub-metodlarga ega asosiy ViewHolder, Fragment yoki ViewController yaratishda buziladi. Kichik sinf asosiy sinf metodlarining yarmini ishlatmasa — meros noto'g'ri tanlangan. Kompozitsiya yoki interfeysni ajratish muammoni to'g'riroq hal qiladi.

LSP testi

Oddiy test LSPni tekshirish uchun: asosiy sinf uchun uning kontraktini tekshiradigan unit-test yozing (qaytariladigan qiymatlar, istisnolar, yon ta'sirlar). Ushbu testni har bir kichik sinf uchun ishga tushiring. Agar test muvaffaqiyatsiz bo'lsa — LSP buzilgan. Bu yondashuv «asosiy sinf kontrakti orqali test qilish» deb ataladi.

Android loyihalarida bunday test ViewModel va Repository uchun foydali. BaseViewModel xatodan oldin Loading holatini kafolatlasa, kichik sinf esa Loadingsiz xato tashlasa — test CI bosqichida LSP buzilishini qayd etadi.

Mobil dasturlashda LSP misollari

ClickListener bilan ishlashning Android misolini ko'rib chiqaylik. LSP buzilishi asosiy implementatsiya biror narsaga kafolat berganda va kichik sinf buni buzganda yuz beradi.

kotlin
// Kafolatli asosiy sinf: onClick chaqiriladi
open class BaseClickListener {
    open fun onClick(view: View) {
        // asosiy ishlov berish
    }
}

// LSP buzilishi: kichik sinf istisno tashlaydigan shart qo'shadi
class RestrictedClickListener : BaseClickListener() {
    override fun onClick(view: View) {
        if (!isLoggedIn) {
            throw IllegalStateException("Not logged in")
        }
        super.onClick(view)
    }
}

// To'g'ri yechim: kontrakt buzilmagan
class ConditionalClickListener : BaseClickListener() {
    override fun onClick(view: View) {
        if (isLoggedIn) {
            super.onClick(view)
        }
    }
}

DataSource protokoli bilan iOS misoli ma'lumot o'rniga nil qaytarish orqali LSP buzilishini ko'rsatadi:

swift
// Kontraktli protokol: ma'lumot yoki xato qaytaradi
protocol DataProvider {
    func fetchData() async throws -> [String]
}

// LSP buzilishi: xatosiz nil qaytaradi
class SilentFailProvider: DataProvider {
    func fetchData() async throws -> [String] {
        return [] // xato o'rniga bo'sh massiv
    }
}

// LSPga to'g'ri rioya qilish
class NetworkProvider: DataProvider {
    func fetchData() async throws -> [String] {
        throw NetworkError.timeout
    }
}

Amaliy qoida: agar kichik sinf asosiy sinf kontraktini bajara olmasa — u kichik sinf bo'lmasligi kerak. Alternativ — minimal kontraktli interfeysni ajratib olish va uni har bir turda o'zicha implementatsiya qilish.

LSP va meros: qachon kompozitsiyani tanlash

Kompozitsiya «dir» (is-a) munosabati noaniq yoki shartli bo'lgan holatlarda merosdan afzal. Klassik misol: Manager Employee mi? Ha. Ammo Square to'g'ri Rectanglemi? LSP «yo'q» deydi. Agar merosning to'g'riligiga shubha qilsangiz — kompozitsiyani tanlang.

Mobil dasturlashda kompozitsiya ko'pincha bog'liqliklarni kiritish orqali ishlatiladi: asosiy sinfdan xatti-harakatni meros olish o'rniga, sinf uni konstruktor orqali oladi. ViewModel Repository dan meros olmaydi, uni bog'liqlik sifatida qabul qiladi. Bu ta'rif bo'yicha LSP buzilishini istisno qiladi — meros yo'q, kontrakt buzilishi ham yo'q.

Merosni kompozitsiya bilan almashtirish kerakligini ko'rsatadigan belgilar: kichik sinf asosiy sinf metodlarining bir qismini ishlatmaydi, kichik sinf metodlarni bo'sh stublar bilan qayta yozadi, mijoz kodi instanceof orqali ob'yekt turini tekshiradi. Bu hollarda meros noto'g'ri tanlangan va LSP buzilgan.

Interfeyslar orqali yechim

Interfeyslar LSP muammosini merossiz hal qiladi: har bir tur faqat kerakli metodlarni implementatsiya qiladi. fly() metodi bo'lgan umumiy Bird asosiy sinfi (Penguin uchmaydi) o'rniga — faqat uchadigan qushlar implementatsiya qiladigan Flyable interfeysi. Penguin fly() metodsiz Bird ni implementatsiya qiladi — LSP buzilmagan.

Android arxitekturasida bu yondashuv ajratilgan interfeyslar UseCase orqali qo'llaniladi: getAll, getById, save, delete metodlari bo'lgan bitta katta UseCase o'rniga — alohida GetItemsUseCase, SaveItemUseCase interfeyslari. Mijoz faqat kerakli interfeysga bog'liq va bu interfeysni implementatsiya qiladigan har bir sinf LSP nuqtai nazaridan to'g'ri.

Tez-tez beriladigan savollar

LSP oddiy merosdan nimasi bilan farq qiladi?

Meros — til mexanizmi, LSP — bu mexanizmdan to'g'ri foydalanish qoidasi. Meros imzolarning muvofiqligini (sintaksis) kafolatlaydi, LSP xatti-harakat muvofiqligini (semantika) talab qiladi. LSPsiz meros ish vaqtida buziladigan polimorfizm beradi.

Kichik sinfdagi null har doim LSPni buzadimi?

Agar asosiy sinf non-null qaytarishni kafolatlasa — ha. Agar kontrakt null ga (ixtiyoriy qiymat) ruxsat bersa — yo'q. LSP null ni taqiqlamaydi, kontraktning zaiflashishini taqiqlaydi. Asosiy sinf hujjatlarini o'rganing va kichik sinf kontraktining mos kelishini tekshiring.

LSP Swift dagi protokollarga qanday qo'llaniladi?

Protokollarga LSP sinflarga o'xshab qo'llaniladi. Protokol implementatsiyasi semantik kontraktga rioya qilishi kerak: agar protokol metodni non-throwing deb belgilasa, implementatsiya xato tashlamasligi kerak. Swift buni kompilyatsiya darajasida tekshirmaydi — javobgarlik dasturchida.

Sealed class ishlatganda LSP buzilishi mumkinmi?

Kotlin da Sealed class — alohida holat, chunki iyerarxiya yopiq va kompilyatorga ma'lum. LSP sealed class ga kamroq qo'llaniladi, chunki barcha kichik turlar when ifodasida aniq sanab o'tilgan. Sealed kichik sinfning xatosi mahalliy bo'ladi, yashirin polimorf xato emas.

Loyihada LSPga rioya qilishni qanday test qilish kerak?

Asosiy sinf uchun uning barcha kichik sinflarida ishga tushadigan parametrlashgan test yozing. Test asosiy xatti-harakat kontraktlarini tekshiradi: qaytariladigan qiymatlar, istisnolar, holatlar. Agar test kichik sinflardan birida muvaffaqiyatsiz bo'lsa — LSP buzilgan. CI da bunday test polimorf kod regressiyasining oldini oladi.

Xulosa

  • LSP (Liskov Substitution Principle) — SOLIDda uchinchi, merosning semantik muvofiqligi haqidagi o'rniga qo'yish printsipi
  • Kichik sinf asosiy sinf kontraktini saqlashi kerak: old shartlar, keyingi shartlar va invariantlar
  • instanceof tekshiruvi va metodlarning bo'sh qayta yozilishi — LSP buzilishining asosiy belgilari
  • Kompozitsiya va interfeyslar meros noto'g'ri bo'lgan joyda LSP muammosini hal qiladi
  • Kvadrat va to'rtburchak muammosi — kichik turlar mos kelmasligining klassik namunasi
  • Kontrakt testi asosiy sinf uchun, barcha kichik sinflarda ishga tushiriladigan, CI da LSP buzilishini aniqlaydi
  • Kotlin da Sealed class yopiq iyerarxiya tufayli LSP xavflarini kamaytiradi

Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz

IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.

Loyihani muhokama qilish

Shuningdek o'qing