Esc
Klaviatura yorliqlari
?Show this help ⌘KSearch tToggle dark/light theme nOpen notes j / kScroll down / up bBack to top /Focus search EscClose panels
Barcha kurslar
Object-Oriented Design
ENRUUZ
Eslatmalar
Current chapter
0 chars
Highlight color
Bob 1

Object-Oriented Design Intervyusi nima?

~4 daq o'qish

Object-oriented design intervyulari texnik yollanishda tobora ommalashib borayotgan texnika hisoblanadi. Bu o'zgarish kompaniyalarning haqiqiy dunyo dastur ishlab chiqarish bilan uyg'un ko'nikmalar ustiga ehtiyojini ko'rsatadi. OOD intervyulari Amazon, Bloomberg va Uber kabi kompaniyalarda muhim ahamiyatga ega bo'lib, amaliy kodlash mashqi hisoblanadi. Ushbu intervyularda siz mantiqli va saqlash mumkin bo'lgan tizimlarni qura olish qobiliyatingiz va object-oriented design tamoyillari hamda shablonlarini qanday samarali qo'llayotganingizni tekshiriladi.

Algoritm intervyularidan farqli o'laroq, ular bitta optimal yechimni talab qiladi, OOD intervyuları ijodiylik uchun joy qoldiradi. Hech qanday universal yechim yo'q, chunki turli xil yondashuvlar hamohang va ishlash rejalashuvini ishlab chiqishi mumkin. Masalan, ba'zi savollari "Parking Lot" yoki "Vending Machine" kabi haqiqiy dunyo tizimlariga qaratilgan, boshqalari esa "Unix File Search" yoki "Tic-Tac-Toe" o'yini kabi abstrakttroq yo'nalishga boradi. Har bir savol sizning ko'nikmalaringizni tekshirish uchun noyob qiyinchiliklar taqdim etadi, ammo ularning barchasi bir xil asosiy bilim va shunga o'xshash intervyu tuzilmasiga asoslanadi.

Whiteboard with design prompts: Design a Parking Lot, Design a Vending Machine, Design Tic-Tac-Toe Game
OOD interview design prompts

Ushbu Kitob Qanday Tuzilgan?

Ushbu qisqa bob OOD intervyu savollari nima ekanligini tushuntiradi. Keyingi, biz OOD intervyulariga yondashish uchun ramkani taqdim etamiz va siz uchun to'liq oxiridan oxirigacha misolni ko'rsatamiz. Keyin, OODda ishlatiladigan umumiy dizayn tamoyillari va shablonlarini yopamiz. Shundan so'ng, kitobning qolgan qismi tipik case study savollarga qaratilgan bo'lib, ularni birma-bir hal qilamiz.

Nima Uchun Kompaniyalar OOD Intervyusini Ishlatadilar?

Kompaniyalar OOD intervyusini tez va samarali kod yozishi mumkin bo'lgan malamalı dasturchilarni yollash uchun ishlatadi. Ular muammo doirasini belgilashgan, talablar va qirrali holatlarni aniqlashtirgan, amaliy, past darajali dizaynlarni yaratadilar va dasturiy mahsulotni tushunish, saqlash va kengaytirish oson bo'ladigan kandidatlarni qidirad.

OOD intervyulari, System Design va Behavioral Questions bilan birga, kompaniyalarga kandidatning darajasini belgilashga yordam beradi. OODda yaxshi natija olish ko'pincha chuqurroq dizayn ko'nikmalarini ko'rsatib, o'rta va senior injenerlarni ajratib turad.

Intervyuerlashtirgichlar odatda quyidagilarni qidirad:

**Mahsulot Sezimi:** Domen bilimini qo'llab-quvvatlab va foydalanuvchi markazli qarorlar qabul qilib, haqiqiy dunyo ehtiyojlarini dasturiy mahsulotga aylantiring.

**Tizim Fikrlashi:** Murakkab tizimni quyi tizimlar va komponentlarga bo'lin. Har birining aniq rollarini belgilab, ular qanday ishlashini aniqlang.

**Qaror Qabul Qilish:** Darhol talablardan tashqari fikirlang, kelajak ehtiyojlarini kutib qoling va moslashuvchanlik bilan dizayn qiling. Quyi ta'mirlar juda murakkab va sodda arasida to'g'ri muvozanani saqlang.

**Kod Sifati:** O'z dizayningizni amalga oshirish uchun toza, mantiqli va saqlash mumkin bo'lgan kod yozing. Shuning uchun zamonaviy OOD savollari kodlashga, diagrammalarni emas, e'tibor beradi.

**OOP Bilimi:** Dasturiy mahsulotni sodda va ishlab chiqarish-tayyor qilish uchun object-oriented texnikalar, SOLID tamoyillari va dizayn shablonlarini ishlating.

**Muloqot:** Aniq savollar bering, munozarani boshqaring, o'z fikrlaringizni yaxshi tushuntiring va yechimlaringizda ishonchli bo'ling.

OOD Intervyulari Kodlash Intervyularidan Qanday Farq Qiladi?

OOD intervyulari va algoritm kodlash intervyulari ikkalasi kod yozishni o'z ichiga oladi, lekin ular turli xil maqsadlarga qaratilgan. Agar siz algoritm intervyulariga oʻzbishsi bo'lsangiz, OOD uchun o'z fikringizni oʻzgartirish kerak. Mana ular qanday farq qiladi:

**Sifatga e'tibor, tezlikka emas**

Algoritm intervyulari eng tezkor yechimni xohlaydi, vaqt va joy samaradorligiga e'tibor beradi. OOD intervyulari toza, saqlash mumkin bo'lgan dasturiy mahsulotni baholaydi. Siz ob'ektlardan foydalanasiz va abstraksiyalar va mantiqa bilan yaxshi tuzilgan kodni yaratasiz, hatto biroz vaqt oladimi, OOD intervyularida bu joyidir. Toza, tartibli kodni intuitiv nomlar bilan yozing, shunda o'z fikrlaringiz qo'shimcha tushuntarisiz ajralib turadi.

**Ob'ektlar bilan dizayn, qadam bilan emas**

Algoritm intervyulari ko'pincha tezda muammolarni hal qilishga sundiradi, shuning uchun siz barcha mantiqni bitta funktsiyada yozishingiz mumkin. OOD intervyulari, boshqa tomondan, ob'ektlarga, ular nima ekanligiga, ular nima qilayotganiga va ular bir-biri bilan qanday o'zaro ta'sir qilayotganiga e'tibor beradi. Bosqich-bosqichni ro'y berish o'rniga, har bir ob'ektning roli va munosabatlarini ko'rib chiqing.

**OOP ko'nikmalarini ko'rsating, nafaqat javoblarni**

Algoritm intervyularida muammoni hal qilish eng muhim. OOD intervyulari ham sizning OOP ko'nikmalaringizni tekshiradi. Encapsulation, inheritance va dizayn shablonlar kabi g'oyalarni o'z yechimingizni qurishda ishlating. SOLID tamoyillarning mustahkam tusunishligi toza, saqlash mumkin bo'lgan tizimlarni loyihalashning razmetasini ko'rsatadi. Ular natijani emas, o'z fikrlash jarayonini baholadilar.

**Kengaytirish mumkin bo'lgan dizaynlarni rejalashtiring, jangari-muddatli hal qilinmagan masalalar emas**

Algoritm intervyulari sizni soat ustida yugurtirib, kelajak oʻzgarishlari uchun rejalashtirishga vaqt qoldirmaydi. OOD intervyularida, eng yaxshi yechim ko'pincha kam kodlashni talab qiladi va jadvalvani tartibga solish sizga yechimingiz kelajak talablarida qanday o'sishini muhokama qilish vaqtini beradi. Yaxshi dizayn minimal qayta ishlash bilan yangilashlarga moslashadi.

OOD Intervyusiga Qanday Tayyorlanish Kerak?

Bu kitob sizni OOD intervyulariga eng so'nggi ko'rishish bilan tayyorlashga yordam beradi. U asoslarni, to'liq bosma-bol ko'rishni va umumiy OOD muammolarning misollarini yechimlar bilan yopadi. Siz o'z ko'nikmalaringizni qurishga boshqa resurslardan ham foydalanishingiz mumkin.

Mana tayyorlanishning bir necha usullari:

**OOP asoslarini o'rganing:** OOPning maqolalarini, o'quv qo'llanmalarini yoki kitoblarini o'qing. Bu sizning intervyu ko'nikmalaringizni va keyinroq ish samaradorligingizni mustahkamlaydi. Encapsulation, inheritance, polymorphism va abstraction kabi soddiq g'oyalardan boshlang. Keyin, onlayn qo'llanmalar yordamida SOLID tamoyillari va dizayn shablonlarini o'rganing.

**Yuqori chastotali muammolarni mashq qiling:** Bu kitob tipik OOD muammolarining misollarini o'z ichiga oladi. Ba'zilari, masalan Parking Lot, haqiqiy dunyo tizimlarini qanday modellashtirishni ko'rsatadi. Boshqalari, masalan Elevator System, murakkab mantiqni sinab ko'radi, yoki masalan Linux File Search, abstraksiya ko'nikmalaringizni tekshiradi. Biz bilan kod yozing, keyin ularni o'z sukut bilan hal qilishga urinib ko'ring va o'z ishingizni ko'rib chiqing.

**Mock intervyu va muloqot amaliyoti:** OOD intervyulari faqat kodlash emas, aniq muloqotni baholadilar. Bizning bo'sm orqali bosma-bol ko'rish bobida asosiy mavzularda maslahatlar taqdim etilgan, lekin o'z dizaynlarini ovoz orqali tushuntirish amaliyotini qiling. Do'sting bilan mock intervyu qiling yoki OOD qilayotganda o'zingizni yozib oling va kod yozayotganingizda dizayn qarorlaringizni tushuntirish amaliyotini qiling.

Person reading ByteByteCode book with speech bubbles: Learn OOP fundamentals, Practice high-frequency problems, Mock interview and practice communication
Three ways to prepare for an OOD interview

Kodni Ishga Tushiring

Ushbu kitobda kiritilgan barcha kod ijroiy. Biz siz repository'ni yuklab olishingiz, kodni ishga tushiringiz va OOD tamoyillarini chuqur anglash uchun yechimlarni sinab ko'rishingizni tavsiya qilamiz. Kodni o'rnatish va ishga tushirish bo'yicha qo'llanma repository README faylida keltirilgan.

GitHub repo havolasi: [github.com/ByteByteGoHq/ood-interview](https://github.com/ByteByteGoHq/ood-interview)

Bob 2

OOD Intervyu uchun Freymvork

~13 daq o'qish

OOD intervyusi uchun aniq freymvorkka ega bo'lish ko'pchilik o'ylaganidan muhimroq. Tuzilmasiz intervyu tartibsiz ketishi va siz ham, intervyuer ham uchun tushunish qiyin bo'lishi mumkin.

Bu bobda ochiq OOD muhokamalarida ishonch bilan harakat qilishga yordam beradigan to'rt bosqichli freymvork taqdim etiladi. U abstrakt talablarni konkret arxitektura yoki kodga aylantirishda yo'l ko'rsatadi, shu bilan birga real cheklovlar ostida o'ylangan murosalarni qilish qobiliyatingizni namoyish etadi.

Shuni yodda tuting: OOD intervyulari juda ko'p qirrali bo'lib, bu freymvork mukammal emas. Tuzilma va kutilmalar intervyuer imtiyozlariga qarab o'zgarishi mumkin, shuning uchun siz moslashuvchan bo'lishingiz va shunga ko'ra harakat qilishingiz kerak bo'ladi.

Freymvorkning o'ziga kirishdan oldin, duch kelishi mumkin bo'lgan OOD intervyularining keng tarqalgan turlarini ko'rib chiqaylik.

OOD Intervyularining Turli Xillari

OOD intervyulari odatda uchta sohadan biriga urg'u beradi, har birida afzal ko'rilgan yetkazib berish formati mavjud. Intervyu boshida intervyuerning kutishlarini "Biz yuqori darajadagi sinf diagrammasiga, kod tuzilmasiga yoki to'liq amalga oshirishga e'tibor qaratayapmizmi?" degan savol bilan bilib oling. Bu savol yondashuvingizni moslashtirishga yordam beradi va vaqt cheklovlari (odatda 45–60 daqiqa) ichida kerakli narsani yetkazishingizni ta'minlaydi. Uchta asosiy yetkazib berish formati:

**UML Diagrammalari:** UML diagrammalari bir vaqtlar standart edi va hali ham tizim dizaynlarini vizual tarzda ifodalash uchun keng qo'llaniladi. UML sinf diagrammasi sinflar o'rtasidagi munosabatlarni, jumladan ularning atributlari, metodlari va o'zaro ta'sirlarini tasvirlashga yordam beradi.

**Kod Skeleti:** Bu yondashuv zamonaviy intervyularda tobora ommalashib bormoqda, chunki u real dunyo dasturiy ta'minot ishlab chiqarishga ko'proq o'xshaydi. U intervyuerlarga kerak bo'lganda amalga oshirish tafsilotlarini ko'rib chiqish imkonini beradi. Bu uslubda siz dizayningiz tuzilmasini to'g'ridan-to'g'ri kodda mos sinf va metod e'lonlari yordamida aniqlab, metod tanalarini amalga oshirmasdan qoldirasiz.

**Ishlovchi Kod:** OOD intervyulariga yangilangan urg'u bilan, intervyuerlar ba'zan to'liq funksional, xatosiz amalga oshirishlarni talab qiladi. Ular test holatlari ham so'rashlari mumkin. Bu yondashuv real sanoat rivojlanishiga eng yuqori ishonchlilik darajasini beradi.

Kutilayotgan yetkazib berish ko'pincha intervyuer imtiyozlariga va vaqt cheklovlariga bog'liq. Agar sizdan ishlovchi kod yaratish so'ralsa, qo'rqmang. Intervyuerlar odatda muammoni ajratilgan vaqt ichida hal qilish mumkin bo'lishini ta'minlash uchun soddalashtirishadi.

> **Maslahat:** OOD intervyusida yo'l oxirgi yetkazib berishdan kam emas. Sukutda kod yozish yaxshi taassurot qoldirmaydi. Buning o'rniga, dizayn fikrlash va muloqot qobiliyatingizni namoyish etish uchun jarayon bo'ylab o'ylangan fikrlarni baham ko'ring.

OOD Intervyusi uchun Yo'llovchi Freymvork

Quyida biz tavsiya qiladigan to'rt bosqich keltirilgan:

Flowchart: 1 Requirements Gathering → 2 Identify Core Objects → 3 Navigate the Design (Class Design + Code) → 4 Deep Dive Topics
OOD Intervyu Freymvorki: 4 bosqichli jarayon

1-Bosqich: Talablarni To'plash (5-10 daqiqa)

Muammo bayonotini chuqur tahlil qilish va asosiy funksional va funksional bo'lmagan talablarni aniqlashdan boshlang. Noaniqliklarni hal qilish, real cheklovlarni belgilash va har qanday taxminlarni tasdiqlash uchun maqsadli savollar bering. Bu siz va intervyuer ko'lam va ustuvorliklar haqida aniq tushunchaga ega bo'lishingizni ta'minlaydi.

2-Bosqich: Asosiy Obyektlarni Aniqlash (3-7 daqiqa)

Talablar aniqlanganidan so'ng, asosiy foydalanish holati tanlang va asosiy obyektlar va ularning o'zaro ta'sirlarini aniqlash uchun uni bosqichma-bosqich ko'rib chiqing. Amaliy yondashuv — talablardagi otlarni obyektlarga (masalan, "parking joyi", "transport vositasi", "chipta") va fe'llarni metodlarga (masalan, "joy belgilash", "to'lovni hisoblash") xaritalash. Bu sodda, ammo tegishli dastlabki dizayn yaratib, tozalash uchun poydevor vazifasini bajaradi.

> **Eslatma:** Foydalanish holati diagrammalari ish jarayonlarini vizuallashtirishga va obyektlar o'rtasidagi munosabatlarni aniqlashtira olsa ham, ko'pchilik OOD intervyulari uchun ixtiyoriydir.

3-Bosqich: Sinf Diagrammasi va Kodini Loyihalash (20-25 daqiqa)

Endi asosiy obyektlar va ularning rollari aniq bo'lganligi sababli, sinf diagrammasini ishlab chiqish va uni kodga qanday tarjima qilishini ko'rsatish vaqti keldi.

Yuqoridan pastga yoki pastdan yuqoriga yondashuvdan foydalanib sinflarni loyihalashdan boshlang:

- **Yuqoridan pastga yondashuv:** Avval yuqori darajadagi komponentlar yoki ota-sinflarni aniqlang, so'ngra ularning atributlari va metodlarini tozalang. - **Pastdan yuqoriga yondashuv:** Avval konkret sinflarni (atributlar, metodlar) aniqlang va u yerdan munosabatlar yarating.

Obyektlar qanday o'zaro ta'sir qilishini va javobgarliklarni past juftlashuv va yuqori bog'liqlik kabi asosiy dizayn tamoyillariga amal qilgan holda qanday taqsimlashini belgilang. Bu bosqichda siz obyekt modelingizni mustahkamlaysiz va uning atributlari hamda metodlarining tafsilotlarini ishlab chiqasiz.

Dizayn o'rnatilgandan so'ng, tuzilma kodga qanday tarjima qilishini ko'rsatish uchun asosiy sinflarni amalga oshiring. Ba'zi hollarda to'liq amalga oshirish shart emas. Agar intervyuer boshqacha talab qilmasa, muhim qismlarga e'tibor qarating.

> **Eslatma:** OOD intervyusining asosiy e'tibori dizayn va kod sifatidadir. Ammo siz vaqt va joy murakkabligi hamda samaradorlikni e'tiborsiz qoldirmasligingiz kerak. Kuchli sinf va munosabat modellashtirish ishlash uchun tegishli ma'lumotlar tuzilmalarini tanlashni o'z ichiga oladi. Masalan, kirish namunasi va ishlash asosida List va Set o'rtasida diqqat bilan tanlang. Xuddi shunday, HashSet va TreeSet ham almashtirib bo'lmaydi. Murakkab to'plamlar yoki joylashtirishni yaxshi bilib oling. Haqiqiy intervyu paytida fikrlaringizni aytib, to'g'ri tanlovni qiling, ammo chuqur tahlilga kirmang yoki o'zingizning to'plamlaringizni ixtiro qilib haddan oshiq optimallashtirmang.

4-Bosqich: Chuqur Sho'ng'ish Mavzulari (10-15 daqiqa, ixtiyoriy)

Dizayningizni asosiy foydalanish holatlari bilan tasdiqlaganingizdan so'ng, chekka holatlarni hal qilish va har qanday nomuvofiqliklarni bartaraf etish uchun uni tozalang. Bu odatda intervyuda chuqur sho'ng'ish boshlaneigan nuqtadir. Intervyuerlar tushunishingizni baholash, dizayn qarorlaringizga e'tiroz bildirish yoki echimingizning yanada ilg'or jihatlarini ko'rib chiqish uchun qo'shimcha savollar berishlari mumkin.

Bosqichma-Bosqich Misol

OOD intervyusi qanday kechishini yaxshiroq tushunish uchun, boshidan oxirigacha real misolni ko'rib chiqaylik. Bu bo'lim intervyuning noaniq muammo tavsifidan tuzilgan va o'ylangan echimga qanday tabiiy ravishda rivojlanishi mumkinligini ko'rsatadi.

1-Bosqich: Talablarni To'plash

Anne, dasturiy muhandis, backend ishi uchun intervyudan o'tmoqda. Intervyuer Beth undan parking joyi tizimini loyihalashni so'raydi va dizaynni taqdim etish uchun unga 45 daqiqa beradi.

Anne muammoni o'zlashtirishdan boshlab, ko'lamni birgalikda tushunish yaratish uchun bir necha aniqlovchi savol beradi. U tezda parking joyining turli xil transport vositalari, band joylar va aniq to'lov hisobini qo'llab-quvvatlashi kerakligini bilib oladi.

**Namunaviy Dialog:**

**Anne:** Parking joyi qanday turdagi transport vositalarini qo'llab-quvvatlashi kerak? Biz mashinalar va mototsikllarni ko'rib chiqayapmizmi?

**Beth:** Ha, shuningdek avtobuslari ham. Har bir avtobus uchta joy egallaydi.

**Anne:** Turli turdagi transport vositalari uchun har xil turdagi to'xtash joylarini loyihalashimiz kerakmi?

**Beth:** Ha, qanday loyihalashni o'zingiz hal qila olasiz.

Anne ko'lam va cheklovlarni aniq belgilash uchun o'ylangan savollar berishni davom ettiradi. U quyidagi keng tarqalgan xatoliklardan qochadi:

- Haddan tashqari aniq yoki ortiqcha batafsil savollar berish. - Ilgari javob berilgan savollarni takrorlash, bu e'tiborsizlikni ko'rsatishi mumkin. - Asosiy muammodan chalg'itadigan aloqasiz yoki haddan tashqari murakkab mavzularni kiritish.

**Samarali Talablar To'plash bo'yicha Maslahatlar**

OOD intervyusining birinchi bir necha daqiqasi hal qiluvchi ahamiyatga ega. Samarali talablar to'plash uchun bir necha maslahat:

**Eng Muhim Talablarga E'tibor Qarating**

Eng muhim talablarga e'tibor qaratishdan va siz ham intervyuer ham muammo ko'lamida muvofiq ekanligingizni tasdiqlashdan boshlang. Anne vazifani aniq tushunganidan so'ng, o'z talqinini tasdiqlash uchun asosiy funksionallikni qayta ifodalab, ro'yxatga oladi:

**Anne:** Tizim transport vositalarini to'xtash va ketishni qo'llab-quvvatlaydi, joy mavjudligini kuzatadi va transport vositasi turi hamda to'xtash muddatiga asoslangan to'lovlarni hisoblaydi. Shuningdek, uch turdagi transport vositalarini qo'llab-quvvatlashi kerak.

**Ko'lamni Aniqlashtirish uchun Misollardan Foydalaning**

Anne talablarni faqat ko'rsatishga tayanish o'rniga muhokamani asoslash va chekka holatlarni aniqlash uchun konkret misollardan foydalanadi. U tizimning kutilayotgan xatti-harakatini to'liq ko'rib chiqish uchun bitta oddiy va bitta murakkabro'q stsenariyni taqdim etadi.

**Oddiy Holat:**

**Anne:** Keling, asosiy stsenariyni ko'rib chiqaylik: mashina joyga kiradi, mavjud joy topadi, to'xtaydi va ikki soatdan keyin ketadi. Tizim joy ajratishi, muddatni kuzatishi va to'lovni hisoblashi kerak.

**Murakkab Holat:**

**Anne:** Endi band joyga kiruvchi avtobusni tasavvur qiling. Ba'zi joylar juda kichik yoki boshqa transport vositalari uchun band. Tizim kelajakdagi mavjudlikni optimallashtirgan holda eng mos mavjud joyni topishi kerak.

Bu qarama-qarshi misollarni ko'rib chiqish orqali Anne noaniqliklarni aniqlashtiradi va intervyuer ham u ham bir xil fikrda ekanligini ta'minlaydi.

Asosiy muammo va uning cheklovlarini yaxshi tushunib, u endi dizayn poydevorini tashkil qiluvchi qurilish bloklari (sinflar, metodlar va atributlar)ni aniqlashga o'tishga tayyor.

2-Bosqich: Asosiy Obyektlarni Aniqlash

Dizaynni boshlash uchun Anne asosiy foydalanish holati bo'ylab yuradi: mashinani to'xtash. Jarayonni ko'rib chiqar ekan, u talablardagi otlar va fe'llarga e'tibor berib tegishli obyektlarni aniqlaydi. Bu uni sodda, ammo samarali dastlabki dizayniga olib keladi.

**Anne:** Mashina kirganida tizim tegishli o'lchamdagi mavjud joyni topadi, uni tayinlaydi, chipta beradi va joyni band deb belgilaydi.

Ikkita yoki uchta vakillik foydalanish holatiga e'tibor qaratib, Anne talablar dizaynni tabiiy ravishda yo'naltirishiga imkon beradi. U to'liqlik o'rniga aniqlik va aloqadorlikni ustuvor qilib, hamma narsani bir vaqtda modellashtirishga urinishdan qochadi.

Foydalanish holati bo'ylab ishlayotganda, u dizaynni maqsadli va minimal saqlaydi. Masalan:

**Beth:** To'liq joy kabi chekka holatlarni qanday hal qilasiz?

**Anne:** Yaxshi savol. Agar hech qanday joy mavjud bo'lmasa, tizim tegishli xabar qaytarishi kerak. Men to'liq dizaynga ega bo'lgach, bu mantiqni tozalayman.

Murakkabro'q mavzular paydo bo'lganda, Anne ular bilan chalg'imasdan shug'ullanadi:

**Anne:** Keling, avvalo asosiy foydalanish holatsini tugataylik. Vaqt bo'lsa, men dizaynni kengaytiraman — strategiya naqshidan foydalanib konfiguratsiyalanadigan narxlashni qo'llab-quvvatlash uchun.

Bu bosqichda Anne maqsadi asosiy obyektlarni aniqlash va ularning javobgarliklarini aniq belgilashdir.

Four class boxes: ParkingLot, ParkingSpot, Vehicle, Ticket
Parking Joyining Asosiy Obyektlari

3-Bosqich: Sinf Dizayni va Kodi

Asosiy obyektlar aniqlanganidan so'ng, Anne sinflarni belgilashni, munosabatlarni chizishni va kodda asosiy tuzilmani amalga oshirishni boshlaydi.

**Sinflarni Belgilash**

U tizimning asosini tashkil etuvchi poydevor komponentlardan boshlanadi. Parking joyi misolida u quyidagilarga e'tibor qaratadi: ParkingLot, ParkingSpot, Vehicle va Ticket.

**Anne:** Asosiy ob'ektlar — ParkingLot, ParkingSpot, Vehicle va Ticket. Har bir joyning o'lcham va mavjudlik kabi atributlari bor, har bir transport vositasining turi bor. Ticket kirish vaqtini kuzatadi va to'lovni hisoblaydi.

So'ngra u munosabatlarni ko'rsatish uchun UML diagrammasini chizadi:

- ParkingLot bir nechta ParkingSpot o'z ichiga oladi. - Har bir ParkingSpot bitta Vehicle ushlab turishi mumkin. - Ticket bir Vehicle ni ParkingSpot ga bog'laydi va vaqtni kuzatadi.

Anne har bir sinf yaxshi belgilangan va inkapsulyatsiya, yagona javobgarlik va meros kabi OOP tamoyillariga rioya qilishini ta'minlaydi:

**Anne:** ParkingLot joylarni kuzatish va transport vositasi oqimini boshqarishni o'z ichiga olgan umumiy tuzilmani boshqaradi. Har bir ParkingSpot o'zining mavjudlik holati va unda to'xtagan transport vositasini boshqaradi.

**Anne:** Biz Vehicle asosiy sinfi bilan Car, Motorcycle va Bus kabi kichik sinflarni aniqlay olamiz, chunki ularning to'xtash talablari va to'lov hisob-kitoblari farq qiladi.

U modelni haddan tashqari murakkablashtirmaslikka harakat qiladi va faqat mazmunli xatti-harakatga ega obyektlarga e'tibor qaratadi.

**Kod Amalga Oshirish**

Dizayn o'rnatilganidan so'ng, Anne sinf ta'riflarini yozadi va tegishli atributlar hamda metod imzolarini qo'shadi. Masalan:

- ParkingLot: joylar to'plamini boshqaradi va topshiriqlarni amalga oshiradi. - ParkingSpot: o'lcham, mavjudlik va tayinlangan transport vositasini kuzatadi. - Ticket: kirish vaqtini saqlaydi va to'lovni hisoblaydi.

Kod yozar ekan, Anne intervyuerga mantiqini tushuntiradi, fikrlash jarayoni shaffof bo'lishini ta'minlaydi. Shuningdek, u rivojlanib borishi bilan dizaynni tasdiqlaydi:

**Anne:** Bu sozlama biz muhokama qilgan asosiy foydalanish holatlarini qamrab oladi. Men uni chekka shartlar ostida ham ushlab turishini tekshiraman.

Tanlovlarini qattiq OOD tamoyillariga asoslashga e'tibor qaratib, Anne amaliy va kengaytirilishi mumkin bo'lgan dizayn yaratadi.

UML class diagram: ParkingLot (composition) ParkingSpot, Ticket (association) ParkingSpot and Vehicle
Parking Joyining Sinf Diagrammasi

4-Bosqich: Chuqur Sho'ng'ish Mavzulari

Bu nuqtada Anne dizayni deyarli tugallandi — batafsil UML diagrammasi yoki izchil kod skeleti shaklida. Yakuniy bosqich — tozalash: dizaynni yuqori darajadan ko'rib chiqish uchun bir qadam orqaga chekinish, chekka holatlarni ko'rib chiqish va yaxshilanishlarni hisobga olish.

**Kamchiliklarni Bartaraf Etish**

**Anne:** Chekka holatlar uchun to'liq joylarni hal qilish va avtobuslarga joylarni guruhlash uchun mantiq qo'shaman. Shuningdek, kassada noto'g'ri chiptalar uchun tekshiruv qo'shaman.

U guruhlangan joy boshqaruvini yoki yirik transport vositalari uchun maxsus mantiqni qo'llab-quvvatlash uchun kerak bo'lganda diagrammasi yoki kodini yangilaydi.

**Dizaynni Umumlashtirish**

**Anne:** Bu dizayn asosiy foydalanish holatlarini qo'llab-quvvatlaydi, turli transport vositasi turlariga miqyoslanadi va asosiy chekka holatlar uchun mantiqni o'z ichiga oladi. Agar vaqt bo'lsa, kun vaqtiga asoslangan dinamik narxlash kabi yaxshilanishlarni o'rganaman.

Bu rekapitulyatsiya uning tushunishini mustahkamlaydi va intervyuerga uning fikrlashining to'liq tasvirini beradi.

**O'ylangan Murosalar Qilish**

Tozalashlar ko'pincha meros vs tarkib, ma'lumotlarni modellashtirish yoki dizayn naqshlari sohalarida murosalarni o'z ichiga oladi. Maqsad faqat "to'g'ri" javobni tanlash emas, balki nima uchun qaror mantiqli ekanligini aniq tushuntirish.

Shuningdek, u qachon "bu yetarlicha yaxshi" deb aytishni va keyinga o'tishni biladi. Agar dizayni asosiy foydalanish holatlarini allaqachon ko'rib chiqgan bo'lsa, u faraziy savollarga yoki haddan oshiq optimallashtiruvga botishdan qochadi.

Agar Intervyu Rejalashtirilganidek Ketmasa Nima Bo'ladi?

Qanchalik yaxshi tayyorlanyangizdan qat'i nazar, real intervyular kamdan-kam hollarda mukammal chiziqli yo'lni kuzatadi. Siz o'zgarayotgan talablar, kutilmagan chuqur sho'ng'ishlar yoki hatto e'tiborsiz intervyuer kabi kutilmagan vaziyatlar bilan duch kelishingiz mumkin. Asosiy narsa — moslashuvchan bo'lish, aniq muloqot qilish va o'ylangan dizayn yetkazishga e'tiborni saqlashdir.

Bu bo'lim OOD intervyularidagi keng tarqalgan qiyinchiliklarni va ishonch hamda mahorat bilan ularni qanday hal qilishni o'rganadi.

**1. O'zgarayotgan Talablar va Kengayayotgan Ko'lam**

Ba'zi intervyularda muammo ko'lami siz oldinga siljiganda kengayishi mumkin. Dizayn yarmi yo'lda bo'lganda intervyuer yangi talablar yoki cheklovlar kiritishi mumkin. Vahima qilmang. Bu ko'pincha ataylab qilingan.

✅ Yangi talabni e'tirof eting va uning ta'sirini qisqacha baholang. Joriy dizayningiz o'zgarishga qanday moslashishi mumkinligini yoki qanday murosalar talab qilinishi mumkinligini tushuntiring. Moslashuvchan, ammo strategik bo'ling — kerak bo'lmasa yechimingizni qayta qurmang. Agar intervyuer muayyan sohani kengaytirishda davom etsa, ehtimol moslashuvchanlik va miqyoslilik sinovdan o'tkazilayotgandir.

**2. Juda Erta Chuqur Sho'ng'ishga Tortilish**

Ba'zan intervyuer kengroq tuzilmani belgilashdan oldin tafsilotlarga sho'ng'ishni xohlashi mumkin. Juda erta juda chuqur borish xavfi — katta rasmni ko'zdan qochirish va vaqt tugashi.

✅ Erta kutishlarni belgilang: "Men yuqori darajadagi umumiy ko'rinishdan boshlayman, keyin kerak yerda chuqurroq sho'ng'iymiz." Vaqt va tuzilmani davriy tekshirib turing. Bir sohada qolganda, ayting: "Hozircha men bu yo'nalishda ketaman. Tizimning qolgan qismini to'ldirish buni tozalash uchun kontekst beradi."

**3. Fikrlash Jarayonini Ifodalashda Qiyinchilik**

Aniq muloqot mustahkam dizayn kabi muhimdir. Agar fikrlaringiz chalkash yoki tushuntirish qiyin bo'lsa, bu yechimingiz ta'sirini zaiflashtirishi mumkin.

✅ Sinf darajasidagi tafsilotlarga kirishdan oldin tizimingizning yuqori darajadagi xulosasiyla boshlang. Vizuallardan foydalaning. Sinf diagrammasi yoki kod skeleti suhbatni boylaydi. Ular qanday ekanligini tasvirlash emas, balki dizayn qarorlarini nima uchun qilganingizga e'tibor qarating.

**4. E'tiborsiz Intervyuer Bilan Ishlash**

Har bir intervyuer faol fikr-mulohaza bermaydi. Ular qiziqishsiz, chalkash yoki jim ko'rinsa, bu sizni yo'ldan chiqarmaslik kerak.

✅ Muloyimlik bilan fikr-mulohaza so'rang: "Biror narsani aniqlashtirish yoki dizaynning muayyan qismiga e'tibor qaratish foydali bo'ladimi?" Agar bu ishlamasa, ishingiz o'z-o'zidan gapirsin. Toza diagrammalar yoki ishlovchi kod yetkazishga e'tibor qarating.

**5. Dizayn Qarorlaringiz Sinovdan O'tkazilganda**

Intervyuerlar tanlovlaringizga e'tiroz bildirishlari keng tarqalgan. Bu yomon belgi emas — bu mantiqingiz va moslashuvchanligingizni namoyish etish imkoniyati.

✅ Xotirjam bo'ling va fikrlash jarayonini tushuntiring. Nuqtangizni qo'llab-quvvatlash uchun konkret misollar yoki real dunyo analogiyalaridan foydalaning. Tegishli bo'lsa, vaqt murakkabligi, kengaytirilishi yoki texnik xizmat ko'rsatish kabi atamalardan foydalanib murosalarni ko'rsating. Muqobillarni taklif qiling: "Men meros va tarkib ikkalasini ham ko'rib chiqdim. Men bu yerda merosni tanladim, chunki..."

**6. Tanish Bo'lmagan Terminologiya Bilan Duch Kelish**

Agar intervyuer siz bilmagan atama yoki tushunchadan foydalansa, taxmin qilishdan ko'ra aniqlashtirish yaxshiroq.

✅ Muloyimlik bilan so'rang: "Bu atama bilan nimani nazarda tutayotganingizni aniqlashtira olasizmi?" Yoki qisman tushunishni ko'rsating va moslashiring: "Bu tushuncha haqidagi tushuncham X. Iltimos, sizning kontekstingizda qanday farq qilishini aytib bering."

**7. To'g'ri Abstraksiya Darajasi Bilan Qiyinchilik**

Qancha tafsilotga kirishni bilmayapsizmi? Bu OOD intervyularidagi keng tarqalgan zo'riqish. Juda keng borish yechimingizni noaniq qilishi mumkin; juda erta juda chuqur borish vaqtni behuda sarflaydi.

✅ Umumiy tuzilmadan boshlang va kerak bo'lganda tafsilotlarni qo'shing. Intervyuerdan qancha chuqurlikni istashini so'rang: "Bu yerda yuqori darajadagi arxitektura yoki batafsilroq sinf taqsimotini afzal ko'rasizmi?"

**8. OOD Intervyularida Parallellikni Ko'rib Chiqish**

Parallellik — bu intervyuerlar, ko'pincha tizimingiz bir vaqtda bir xil resurslarga kiruvchi bir nechta foydalanuvchilar yoki jarayonlarni qanday boshqarishini so'rab ko'taradigan ilg'or mavzu.

Klassik misol — chipta bronlash tizimi: asosiy muammo bir nechta foydalanuvchi bir xil o'rindiqni tanlashga uringanida ikki marta bronlashning oldini olishdir. Bu stsenariy qulflash, optimistik qulflash yoki tilga xos sinxronizatsiya mexanizmlari va parallel ma'lumotlar tuzilmalaridan foydalanish kabi texnikalarni ko'rsatish uchun ajoyib imkoniyatdir.

Tushuntirishingizni qisqa saqlang va amalga oshirishingizni sodda. Ko'p intervyularda, parallellik strategiyangizning yuqori darajadagi tavsifi va poyga shartlarini qanday oldini olishingizni ko'rsatadigan qisqa kod parchasi bilan birga, bu yetarlicha.

Ba'zi hollarda tizimingizning o'zi parallel ishlashi kerak bo'lishi mumkin. Agar Java-da kod yozsangiz, Thread, Runnable, Callable va ExecutorService kabi sinflarni tushunish qimmatlidir, chunki bu sizga parallellikni past darajali primitivlardan qayta ixtiro qilmaslikka yordam beradi.

Yakuniy Fikrlar

Ob'ektga yo'naltirilgan dizayn intervyusi texnik ko'nikmalardan ko'proq narsadir. Bu bosim ostida aniq fikrlash, samarali muloqot qilish va texnik xizmat ko'rsatish mumkin bo'lgan, miqyoslanadigan yechimlar yaratish uchun OOP tamoyillarini qo'llash haqida.

Jarayonni boshqariladigan bosqichlarga bo'lish va kutilmagan qiyinchiliklarni qanday boshqarishni o'rganish orqali, hatto eng oldindan aytib bo'lmaydigan intervyularni ham hal qilishga tayyor bo'lasiz. Mashq va to'g'ri fikrlash bilan siz kutilmagan vaziyatlarni imkoniyatlarga aylantira olasiz va kuchli taassurot qoldirasiz.

Bob 3

OOP Asoslari

~19 daq o'qish

Bu bob kodni va ma'lumotlarni obyektlarga tashkil etuvchi mashhur dasturlash paradigmasi bo'lgan OOP ni tanishtiradi. Bu obyektlar vazifalarni bajarish va real dunyo ob'ektlarini modellashtirishga hamkorlik qiladi, moslashuvchan va texnik xizmat ko'rsatish mumkin bo'lgan dasturiy ta'minotni yaratishda tizimli yondashuvni ta'minlaydi.

Nima Uchun OOP ni O'rganish Kerak?

Asosiy tamoyillar — inkapsulyatsiya va SOLID kabi ilg'or dizayn ko'rsatmalari bilan OOP asoslarini tushunish OOD intervyularida muvaffaqiyat qozonishning kalitidir. OOP bilimlari sizni aniq aqliy model va poydevor ko'nikmalar bilan ta'minlaydi. U sizni keng qabul qilingan tamoyillarga mos keladigan dizayn qarorlarini qabul qilish, intervyuerlarga mantiqingizni ifodalash va keng tarqalgan muammolarni samarali hal qilish uchun mavjud naqshlardan foydalanish imkonini beradi.

OOP intervyulari ko'pincha real dunyo biznes ilovalari va texnik komponentlarini aks ettiradi. OOP tushunchalari va SOLID ko'rsatmalarini tushunish sizni nafaqat intervyularga tayyorlab qolmasdan, balki yollangandan so'ng kuchliroq dasturchi qiladi. Funksional dasturlash va boshqa paradigmalar tobora ommalashib borsa ham, OOP umumiy dasturiy ta'minot ishlab chiqarishning asosi bo'lib qolmoqda. Tajribangizni chuqurlashtirish uchun ushbu bobning asosiy qismlarini OOP tamoyillariga oid qo'shimcha manbalar bilan to'ldiring.

Ob'ektga Yo'naltirilgan Dasturlashning Tosh Poydevori

Ob'ektga yo'naltirilgan dasturlash to'rtta asosiy tamoyil ustiga qurilgan: Inkapsulyatsiya, Abstraksiya, Meros va Polimorfizm.

Bu tamoyillar kodni qanday tashkil qilishimiz va dasturiy ta'minotni qanday loyihalashimizga yo'l ko'rsatadi. Boshqa texnikalar va dizayn naqshlari ushbu tamoyillardan kelib chiqadi va ular echimlarni baholash uchun muhimdir. Keling, har bir tamoyilni amaliy misollar bilan ko'rib chiqaylik.

Four-petal diagram showing Encapsulation, Abstraction, Inheritance, and Polymorphism as the four cornerstones of OOP
OOP ning Tosh Poydevori

Inkapsulyatsiya

Inkapsulyatsiya — ma'lumotlarni atributlar sifatida va mantiqni metodlar sifatida birlashtirish, so'ngra tegishli atributlar va metodlarni obyekt deb ataladigan yagona birlikda joylashtirish kontseptsiyasidir. Obyektning ichki holati tashqi dunyodan yashirilgan va ma'lumotlarga yoki holatga kirish ommaviy metodlar sifatida mavjud bo'lgan yaxshi belgilangan interfeyslar orqali boshqariladi. Ob'ekt turining tavsifi sinf deb ataladi, aniq ob'ekt esa namunaа deb ataladi.

Inkapsulyatsiya amalda qanday ishlashini ko'rish uchun Person sinfini ko'rib chiqaylik, u ism va yosh kabi ma'lumotlarni ularni boshqarish uchun metodlar bilan birlashtiradi, ma'lumotlarga kirishni nazorat qiladi.

### Inkapsulyatsiyaga qanday erishish mumkin?

Inkapsulyatsiyaga erishish uchun quyidagi amallarni bajaring:

1. **Sinflarni aniqlang:** Talablardagi obyektlarni aniqlang, ular saqlaydigan ma'lumotlar va qo'llab-quvvatlaydigan funksionallik haqida o'ylang. Person sinfi uchun ma'lumotlar ism va yosh, funksionallik esa ushbu atributlarga kirish va ularni o'zgartirishni o'z ichiga oladi. 2. **Inkapsulyatsiyani ta'minlang:** Sinfning ma'lumotlar a'zolarini (atributlarini) sinfdan tashqaridan to'g'ridan-to'g'ri kirishni cheklash uchun private sifatida e'lon qiling. Ushbu atributlarga kirish va ularni o'zgartirish uchun ommaviy metodlar (getterlar va setterlar) taqdim eting. 3. **Kirish modifikatorlaridan foydalaning:** Private kirish modifikatori sinfdan tashqarisidagi atributlarga to'g'ridan-to'g'ri kirishni cheklaydi. Faqat sinfidagi metodlar ushbu private a'zolarga kirish huquqiga ega. Ommaviy metodlar — tashqi kodning obyekt atributlari bilan o'zaro ta'sir qilish interfeysi bo'lib, ichki amalga oshirish tafsilotlarini yashiradi va obyektning yaxlitligini saqlaydi.

### Java-da inkapsulyatsiyani amalga oshirish

Keling, "Person" ni ifodalovchi oddiy sinf bilan Java-da inkapsulyatsiyani ko'rsataylik:

```java public class Person { // Private ma'lumotlar a'zolari (atributlar) private String name; private int age;

// Ommaviy konstruktor public Person(String name, int age) { this.name = name; this.age = age; }

// Ommaviy getter metodlari (accessors) public String getName() { return name; }

public int getAge() { return age; }

// Ommaviy setter metodlari (mutators) public void setName(String name) { this.name = name; }

public void setAge(int age) { if (age >= 0) { this.age = age; } } } ```

- Person sinfida `name` va `age` private atributlari mavjud bo'lib, ular sinfdan tashqarida to'g'ridan-to'g'ri kirilib bo'lmaydi. - `getName()` va `getAge()` ommaviy getter metodlari tashqi kodga private atributlarni o'qish (kirish) imkonini beradi. - `setName()` va `setAge()` setter metodlari ham ommaviy bo'lib, tashqi kodga private atributlarni o'zgartirish (mutatsiya) imkonini beradi.

Bu amalga oshirish Person obyektining ichki holati himoyalanganligini ta'minlaydi va tashqi kod u bilan faqat nazorat qilinadigan metodlar orqali o'zaro ta'sir qiladi.

### Inkapsulyatsiyadan qachon foydalanish kerak?

Inkapsulyatsiya quyidagi holatlarda ayniqsa foydali:

- **Ma'lumotlar yaxlitligini himoya qilish:** Ob'ekt ma'lumotlari izchil va to'g'ri qolishini ta'minlashingiz kerak bo'lganda. Masalan, Person sinfida inkapsulyatsiya ismni va yoshni private atributlar sifatida yashiradi, setAge() metodiga nomanfiy qiymatlar kabi qoidalarni ta'minlashga, noto'g'ri o'zgartirishlarni oldini olishga va obyektning holatini ishonchli bo'lishini ta'minlashga imkon beradi. - **Kirishni nazorat qilish va xavfsizlikni yaxshilash:** Inkapsulyatsiya nozik ma'lumotlarga to'g'ridan-to'g'ri kirishni cheklaydi. Person sinfidagi ism va yosh kabi atributlar juda nozik bo'lmasa ham, inkapsulyatsiya parollar kabi muhim ma'lumotlarni boshqaruvchi sinflar uchun muhim bo'ladi. Inkapsulyatsiya to'liq xavfsizlikni kafolatlamasa ham, u istalmagan kirishni cheklash orqali poydevor qatlam vazifasini bajaradi. - **Modullilik va qayta foydalanish imkoniyati:** Turli ilovalarda qayta foydalanish mumkin bo'lgan sinflarni loyihalashda. Person sinfining aniq interfeysi uni maktab boshqaruvi yoki ijtimoiy tarmoq tizimlari kabi kontekstlarda modulli va qayta foydalanish mumkin qiladi.

### Keng tarqalgan tuzog'lar

Inkapsulyatsiya kuchli bo'lsa-da, ushbu keng tarqalgan xatolardan saqlaning:

- **Haddan oshiq inkapsulyatsiya:** Har bir atribut uchun ortiqcha getter va setter metodlar yaratish kodni og'irroq va texnik xizmat ko'rsatishni qiyinlashtirishi mumkin. - **Kamroq inkapsulyatsiya:** Ichki tafsilotlarni yashiramaslik qattiq juftlashga va modullilik pasayishiga olib kelishi mumkin. Masalan, Person sinfidagi ism va yosh ommaviy bo'lsa, kodning boshqa qismlari ularni bevosita o'zgartira oladi va bu nomuvofiqliklarga olib kelishi mumkin.

Abstraksiya

Abstraksiya keraksiz tafsilotlarni yashirish orqali murakkab tizimlarni soddalashtirishi mumkin. U "nima" ob'ekt qilishini "qanday" qilishidan ajratadi va foydalanuvchilarga soddalashtirilgan interfeyslar orqali ob'ektlar bilan o'zaro ta'sir qilish imkonini beradi. Masalan, televizor pultidagi ovoz bajarilish tugmasi televizorning ichki sxemasini ko'rsatmasdan ovozni sozlashning oddiy usulini beradi. Dasturlashda abstraksiya mavhum sinflar va interfeyslar kabi mexanizmlar yordamida erishiladi.

Abstraksiya amalda qanday ishlashini ko'rish uchun Shape sinfi va Drawable interfeysini ko'rib chiqaylik, ular doiralar kabi shakllar uchun soddalashtirilgan xatti-harakatlarni belgilaydi.

### Abstraksiyaga qanday erishish mumkin?

Abstraksiyaga erishish uchun mavhum sinflar va interfeyslardan foydalaning: Mavhum metodlarga ega mavhum sinflar yoki interfeyslarni aniqlang. Bu metodlar amalga oshirilmasdan e'lon qilinib, kichik sinflar tomonidan amalga oshirilishi kerak. Bular foydalanuvchilarga ularning ichki tafsilotlarini bilmasdan metodlarni chaqirish imkonini beradi.

### Java-da Abstraksiyani Amalga Oshirish

Keling, Shape ni ifodalovchi mavhum sinf va Drawable ob'ektni ifodalovchi interfeys bilan Java-da abstraksiyani ko'rsataylik:

```java // Mavhum sinf abstract class Shape { protected String color;

public Shape(String color) { this.color = color; }

// Mavhum metod public abstract double area();

// Konkret metod public void displayColor() { System.out.println("Bu shakl " + color + " rangda."); } }

// Interfeys interface Drawable { void draw(); }

// Shape va Drawable ni amalga oshiruvchi konkret sinf class Circle extends Shape implements Drawable { private double radius;

public Circle(String color, double radius) { super(color); this.radius = radius; }

// Shape dan mavhum metodning amalga oshirilishi @Override public double area() { return Math.PI * radius * radius; }

// Drawable interfeysidan metodning amalga oshirilishi @Override public void draw() { System.out.println("Doira chizilmoqda."); } } ```

Amaliy misol abstraksiyani quyidagilar orqali ko'rsatadi:

- Shape mavhum sinfi kichik sinflar amalga oshirishi kerak bo'lgan mavhum `area()` metodini va standart xatti-harakatni ta'minlovchi konkret `displayColor()` metodini belgilaydi. - Drawable interfeysi amalga oshiruvchi sinflar belgilashi kerak bo'lgan `draw()` metodini e'lon qiladi. - Circle sinfi Shape ni kengaytiradi va Drawable ni amalga oshiradi, `area()` (doira maydonini hisoblash) va `draw()` (chizish amalini tasvirlash) uchun maxsus amalga oshirishlarni taqdim etadi.

Bu tuzilma foydalanuvchilarga asosiy chizish mantig'ini bilmasdan `area()` va `draw()` kabi yuqori darajadagi metodlar yordamida shakllar bilan o'zaro ta'sir qilish imkonini beradi.

### Abstraksiyadan qachon foydalanish kerak?

Abstraksiya quyidagi holatlarda ayniqsa foydali:

- **Murakkab tizimlarni soddalashtirish:** Abstraksiya murakkab funksionallik uchun toza va izchil interfeys ta'minlashga yordam beradi. Masalan, Shape sinfida abstraksiya foydalanuvchilarga matematik hisob-kitoblarni tushunmasdan `area()` ni chaqirish imkonini beradi va tizimni ishlatishni osonlashtiradi. - **Kod moslashuvchanligini oshirish:** Kichik sinflar umumlashtirilgan xatti-harakatning maxsus amalga oshirishlarini ta'minlashini kutganda, abstraksiya muhim ahamiyat kasb etadi. Shape sinfining mavhum `area()` metodi doiralar yoki to'rtburchaklar kabi shakllar o'z maydon hisob-kitoblarini amalga oshirishini ta'minlaydi va dizaynda moslashuvchanlikka imkon beradi. - **Kengaytirilishni qo'llab-quvvatlash:** Abstraksiya mavjud kodni o'zgartirmasdan tizimlarni kengaytirishni osonlashtiradi. Masalan, Shape ierarxiyasiga Triangle kabi yangi shakl qo'shish faqat `area()` ni amalga oshirishni talab qiladi, shakllardan foydalanadigan mavjud kodni o'zgartirmasdan.

### Abstraksiya va Inkapsulyatsiya

Abstraksiya va inkapsulyatsiya — ikkalasi ham tafsilotlarni yashirishni o'z ichiga olganligi sababli tez-tez chalkashtirib yuborilgan alohida, ammo bir-birini to'ldiruvchi OOP tamoyillaridir. Ularning qanday farq qilishi:

| Xususiyatlar | Abstraksiya | Inkapsulyatsiya | |---|---|---| | E'tibor | Ob'ekt nimа qilishini soddalashtirilgan interfeyslar orqali ko'rsatib, qanday qilishini oshkor etmasdan murakkablikni yashirish. | Ma'lumotlar va metodlarni yagona birlikka (sinf) birlashtirish va to'g'ridan-to'g'ri kirishni cheklash orqali ma'lumotlarni himoya qilish. | | Maqsad | Yuqori darajadagi xatti-harakatlarni belgilash orqali foydalanuvchi muloqotini soddalashtiradi va moslashuvchanlikni oshiradi. | Ob'ekt ma'lumotlariga kirishni nazorat qilish orqali ma'lumotlar yaxlitligi va texnik xizmat ko'rsatishni ta'minlaydi. | | Amalga oshirish | Mavhum sinflar va interfeyslardan foydalanadi, masalan, `area()` li Shape mavhum sinfi yoki `draw()` li Drawable interfeysi. | Kirish modifikatorlaridan (masalan, private, public) va metodlardan foydalanadi, masalan, ommaviy getterlar va setterlar bilan Circle da private radius. |

Bu farqlarni tushunib, siz interfeyslarni soddalashtirish uchun abstraksiyani va ma'lumotlarni himoya qilish uchun inkapsulyatsiyani qo'llay olasiz, mustahkam va foydalanuvchilarni e'tiborga olgan tizimlar yaratib.

Meros

Meros sinfga (kichik sinf yoki kelib chiqilgan sinf) boshqa sinfdan (ota-sinf yoki asosiy sinf) xususiyatlar va xatti-harakatlarni meros qilib olish imkonini beradi. U kodni qayta ishlatishni rag'batlantiradi va sinflar o'rtasida ierarxik munosabat yaratadi. Merosni oila daraxti kabi tasavvur qiling: bolalar ota-onalaridan xususiyatlarni meros oladi, nabiralar esa ham ota-onalaridan, ham bobolaridan xususiyatlarni meros oladi. Kichik sinf ota-sinfining funksionalligini kengaytira va ixtisoslashtira oladi, kod takrorlanishini kamaytiradi.

### Sinf ierarxiyasining keng tarqalgan naqshlari

Meros kontseptsiyasidan kelib chiqib, endi Java-da sinf ierarxiyalarini tuzishning keng tarqalgan naqshlarini ko'rib chiqamiz.

**Yakka meros** — Kichik sinf faqat bitta ota-sinfni kengaytiradi. Bu Java-da qo'llab-quvvatlanadigan standart meros turidir.

**Ko'p bosqichli Meros** — Boshqa kichik sinfdan meros oluvchi kichik sinf, meros zanjirini hosil qiladi. Animal ota-sinf sifatida Mammal ning va Mammal esa Dog ning ota-sinfi bo'lgan uch sinfli stsenariyni ko'rib chiqing.

**Ierarxik Meros** — Bir nechta kichik sinflar bitta ota-sinfdan meros oladi, ierarxik tuzilma hosil qiladi. Masalan, Car va Motorcycle ikkalasi ham Vehicle sinfidan meros oladi.

### Merosdan qachon foydalanish kerak?

Meros quyidagi holatlarda ayniqsa foydali:

- Ob'ektlar o'rtasida "bu" munosabatiga duch kelganimizda. - Bir nechta sinf umumiy atributlarga yoki metodlarga ega bo'lganda, ota-sinf ularni bir marta belgilay oladi va barcha kichik sinflarga ularga meros olish va takrorlanishni oldini olish imkonini beradi. - Sinflar Animal, Dog va Cat ga ota bo'lgani kabi tabiiy ierarxiya hosil qilganda.

### Merosning kamchiliklari

Meros kodni qayta ishlatishni rag'batlantirsada, uni haddan oshiq ishlatish dizaynlarni murakkablashtirishi mumkin:

- **Qattiq juftlashuv:** Kichik sinflar ota-sinflariga qattiq bog'liq. Ota-sinfga o'zgartirishlar kichik sinflarni buzishi mumkin, kodni texnik xizmat ko'rsatishni qiyinlashtiradi. - **Nomuvofiq xatti-harakat merosi:** Meros kichik sinflarga qo'llanilmaydigan xatti-harakatlarni meros olishga majbur qilishi mumkin. Masalan, Animal ota-sinfiga `fly()` metodi qo'shish barcha kichik sinflar (masalan, Penguin) uchul uchishi mumkin deb taxmin qiladi. - **Cheklangan moslashuvchanlik:** Meros munosabatlarni dizayn vaqtida qulflaydi. Keyinchalik hurmaydigan, ammo ovqatlanmaydigan RobotDog kerak bo'lsa, u aloqasiz metodlarni meros olmay Animal dan meros ola olmaydi.

Bu muammolarni hal qilish uchun tarkib (ob'ektlarni birlashtirish) yoki moslashuvchanlik va erkin juftlashuv taklif qiluvchi interfeyslar kabi muqobillarni ko'rib chiqing.

### Meros va Tarkib

Meros "bu" munosabatni yaratadi. Tarkib sinfning boshqa ob'ektlarni o'z ichiga olganligi va xatti-harakatlarni ta'minlovchi "ega" munosabatni yaratadi.

Dog va RobotDog stsenariyini ko'rib chiqing. Merosdan foydalanib, RobotDog `bark()` ni meros olish uchun Animal ni kengaytiradi, ammo qo'llanilmaydigan `eat()` ni ham oladi. Tarkibdan foydalanib, `bark()` metodiga ega BarkBehavior interfeysini belgilaysiz. Dog va RobotDog har biri turlicha amalga oshirilgan BarkBehavior ob'ektiga ega (masalan, "Woof!" uchun DogBark va "Beep!" uchun RobotBark). Bu RobotDog ga `eat()` meros olmay hurishga imkon beradi.

```java interface BarkBehavior { void bark(); }

class DogBark implements BarkBehavior { public void bark() { System.out.println("Woof!"); } }

class RobotBark implements BarkBehavior { public void bark() { System.out.println("Beep!"); } }

class Dog { private BarkBehavior barkBehavior;

public Dog(BarkBehavior barkBehavior) { this.barkBehavior = barkBehavior; }

public void bark() { barkBehavior.bark(); } }

class RobotDog { private BarkBehavior barkBehavior;

public RobotDog(BarkBehavior barkBehavior) { this.barkBehavior = barkBehavior; }

public void bark() { barkBehavior.bark(); } }

public class Main { public static void main(String[] args) { Dog dog = new Dog(new DogBark()); RobotDog robotDog = new RobotDog(new RobotBark()); dog.bark(); // Chiqish: Woof! robotDog.bark(); // Chiqish: Beep! } } ```

> **Dizayn Tanlovi:** Barqaror, umumiy xatti-harakatlar bilan aniq "bu" munosabatlar uchun merosdan foydalaning. "Ega" munosabatlar yoki moslashuvchan, almashtiriladigan xatti-harakatlar kerak bo'lganda tarkibni tanlang, chunki uni o'zgartirish va texnik xizmat ko'rsatish osonroq. OOD intervyularida moslashuvchanlik yoki erkin juftlashuv asosiy bo'lganda tarkibni afzal ko'ring, chunki bu zamonaviy dizaynda afzal ko'riladi.

Class diagram showing Dog extends Animal with single inheritance
Yakka meros
Class diagram showing Dog extends Mammal extends Animal — multilevel inheritance chain
Ko'p bosqichli meros
Class diagram showing Car and Motorcycle both extending Vehicle — hierarchical inheritance
Ierarxik meros

Polimorfizm

Polimorfizm — hamma umumiy interfeys doirasida ob'ektlarni ko'p shaklni qabul qilish yoki kontekstiga qarab turlicha xatti-harakat qilish sifatida amalga oshirish kontseptsiyasidir. U mavjud kodni o'zgartirmasdan yangi xatti-harakatlarni qo'shish moslashuvchanligini beradi.

Media pleyer haqida real dunyo misolini ko'rib chiqing. Audio, video va oqimli kontent kabi turli media turlarini bir xil ko'rsatish vidjetida ijro etish va bir xil "play" tugmasi bilan boshqarish mumkin bo'ladi. Ammo ular har xil ichki ishlov berish va ko'rsatish mantiqini talab qiladi. Foydalanuvchi faqat bir xil interfeys bilan muloqot qiladi, polimorfik xatti-harakat esa turli ob'ektlarni boshqaradi.

### Polimorfizm Turlari

Polimorfizm odatda ikki asosiy turga bo'linadi: kompilyatsiya vaqti (statik) va ish vaqti (dinamik) polimorfizm.

**Metod yuklanishi orqali kompilyatsiya vaqti polimorfizmi** — Metod yuklanishi sinfga bir xil nomga ega, ammo har xil parametrli bir nechta metodga ega bo'lish imkonini beradi. Kompilyator kompilyatsiya vaqtida o'tkazilgan argumentlar soni va turiga qarab chaqiriladigan tegishli metodii aniqlaydi.

```java class MathOperations { public int add(int a, int b) { return a + b; }

public double add(double a, double b) { return a + b; }

public String add(String str1, String str2) { return str1 + str2; } }

public class Main { public static void main(String[] args) { MathOperations math = new MathOperations();

int sum1 = math.add(5, 10); double sum2 = math.add(3.5, 7.2); String result = math.add("Salom, ", "Dunyo!");

System.out.println("Butun sonlar yig'indisi: " + sum1); System.out.println("Kasrlar yig'indisi: " + sum2); System.out.println("Birlashtirilgan satr: " + result); } } ```

MathOperations sinfi har xil parametr turlari yoki soni bilan bir nechta `add` metodini belgilaydi. Kompilyator o'tkazilgan argumentlarga qarab tegishli `add` metodini tanlaydi, kod o'qilishini yaxshilaydi.

**Metod qayta belgilash orqali ish vaqti polimorfizmi** — Metod qayta belgilash kichik sinf ota-sinfida allaqachon belgilangan metod uchun maxsus amalga oshirishni taqdim etganda yuzaga keladi. Bajariladigan metod ob'ektning haqiqiy turiga qarab ish vaqtida aniqlanadi. Bu ko'pincha dinamik yuborish deb ataladi.

```java class Animal { public void sound() { System.out.println("Hayvon tovush chiqaradi."); } }

class Dog extends Animal { @Override public void sound() { System.out.println("It huradi: Woof!"); } }

class Cat extends Animal { @Override public void sound() { System.out.println("Mushuk miyovlaydi: Miyov!"); } }

public class Main { public static void main(String[] args) { Animal animal1 = new Dog(); Animal animal2 = new Cat();

animal1.sound(); // Dog ning sound() metodi chaqiriladi animal2.sound(); // Cat ning sound() metodi chaqiriladi } } ```

- Animal sinfi umumiy `sound` metodini belgilaydi. - Dog va Cat kichik sinflari maxsus amalga oshirishlarni ta'minlash uchun `sound` ni qayta belgilaydi. - Ish vaqtida JVM ob'ektning haqiqiy turini (Dog yoki Cat) aniqlaydi va havolaning turi Animal bo'lsada, tegishli `sound` metodini chaqiradi.

### Polimorfizmdan qachon foydalanish kerak?

Polimorfizm quyidagi holatlarda ayniqsa qimmatli:

- **Umumiy Interfeys:** Bir nechta sinf turli media turlari uchun `play` metodi kabi bir xil harakatni turlicha bajarishi kerak bo'lganda. Interfeyslar yoki ota-sinflar amalga oshirishlar bo'ylab izchil shartnomani ta'minlaydi. - **Kengaytirilish:** Mavjud kodni o'zgartirmasdan yangi sinflarni moslashtiradigan tizimlarni loyihalashda. Yangi media turini qo'shish faqat mavjud play interfeysini amalga oshirishni talab qiladi. - **Moslashtirishga imkon berish:** Kichik sinflar meros olingan metodlar xatti-harakatini moslashtirishi kerak bo'lganda. Masalan, Dog ning Cat dan farqli hurishi Animal interfeysiga rioya qilgan holda maxsus amalga oshirishlarni ta'minlash uchun metodning qayta belgilashdan foydalanadi.

SOLID Yaxshi Dizayn Tamoyili

Asosiy OOP tamoyillaridan (inkapsulyatsiya, abstraksiya, meros va polimorfizm) tashqari, SOLID tamoyillari bilan ham tanish bo'lishingiz kerak. SOLID tushunish, o'zgartirish va kengaytirish oson bo'lgan dasturiy ta'minotni yaratish uchun ko'rsatmalar taklif etadi. Bu tamoyillar, ayniqsa dizayn qarorlarini va ularning asosini ifodalash foydangizga bo'ladigan OOD intervyularida ayniqsa qimmatlidir.

SOLID qisqartmasi quyidagilarni anglatadi:

- **S** — Yagona Javobgarlik Tamoyili (SRP) - **O** — Ochiq/Yopiq Tamoyil (OCP) - **L** — Liskov Almashtirish Tamoyili (LSP) - **I** — Interfeys Ajratish Tamoyili (ISP) - **D** — Bog'liqliklarni Teskari Yo'naltirish Tamoyili (DIP)

Diagram showing the SOLID acronym with all five principles listed
SOLID Tamoyillari

Yagona Javobgarlik Tamoyili (SRP)

Yagona Javobgarlik Tamoyili (SRP) sinfning o'zgarish uchun faqat bitta sababga ega bo'lishi kerakligini — dasturiy ta'minot tizimida yagona, yaxshi belgilangan javobgarlik yoki vazifaga ega bo'lishi kerakligini bildiradi.

**SRP ni buzish**

Quyida bir nechta javobgarlikni o'z zimmasiga olish orqali SRP ni buzuvchi sinf misoli keltirilgan:

```java class Employee { private String name; private double salary;

public Employee(String name, double salary) { this.name = name; this.salary = salary; }

public double calculateSalary() { return salary * 12; // Yillik maosh }

public void generatePayrollReport() { System.out.println("Ish haqi hisoboti " + name + " uchun: $" + salary * 12); } } ```

Employee sinfi SRP ni buzadi, chunki unda ikki javobgarlik bor: xodim maoshini hisoblash va ish haqi hisobotini yaratish. Bu sinfning ikki aloqasiz sababga ko'ra o'zgarishi mumkinligini anglatadi.

**Buzilishni tuzatish**

Buzilishni bartaraf etish uchun kodni alohida tashvishlarga ajratib refaktorlang:

- `Employee` sinfi xodim ma'lumotlarini (ism, maosh) boshqaradi va yillik maoshni hisoblaydi. - `PayrollReportGenerator` sinfi xodim ma'lumotlarini oladi va ish haqi hisobotlarini yaratadi.

Bu ajratish maosh hisob-kitoblaridagi o'zgartirishlar hisobotga ta'sir qilmasligini va hisobot formatlaridagi yangilanishlar xodim ma'lumotlariga ta'sir qilmasligini ta'minlaydi.

**Eng yaxshi amaliyotlar**

- Har bir sinfning aniq rolini belgilashga harakat qiling, bitta muayyan vazifaga e'tibor qarating. - Agar sinf bir nechta vazifani bajarganda, uni yagona javobgarlikli kichik, maqsadli sinflarga ajrating. - Bitta vazifaga o'zgartirishlar boshqalarga ta'sir qilmasligi uchun sinflarni loyihalang.

Class diagram showing Employee and PayrollReportGenerator as separate classes adhering to SRP
Yagona Javobgarlik Tamoyili (SRP)

Ochiq/Yopiq Tamoyil (OCP)

Ochiq/Yopiq Tamoyil (OCP) dasturiy ta'minot ob'ektlari kengaytirish uchun ochiq, ammo o'zgartirish uchun yopiq bo'lishi kerakligini bildiradi. Bu mavjud kodni o'zgartirmasdan yangi funksionallik qo'shish mumkin degan ma'noni anglatadi.

**OCP ni buzish**

Quyida yangi shakllarni qo'llab-quvvatlash uchun o'zgartirishlarni talab qilish orqali OCP ni buzuvchi sinf misoli:

```java class Rectangle { private double width; private double height;

public Rectangle(double width, double height) { this.width = width; this.height = height; }

public double calculateArea() { return width * height; } }

class AreaCalculator { public double calculateArea(Rectangle rectangle) { return rectangle.calculateArea(); } } ```

`AreaCalculator` sinfi faqat Rectangle ob'ektlari bilan ishlaydi. Doiralar yoki uchburchaklar kabi yangi shakllarni qo'llab-quvvatlash uchun kodini o'zgartirish talab qilinadi.

**Buzilishni tuzatish**

Umumiy xatti-harakatni belgilovchi mavhum Shape sinfini kiritish orqali refaktorlang:

- Rectangle va Circle kabi muayyan shakllar Shape dan meros oladi va o'z maydon hisob-kitoblarini taqdim etadi. - Bu dizayn Triangle kabi yangi shakllarning Shape dan meros oladigan yangi sinflar yaratib qo'shilishiga imkon beradi, `AreaCalculator` yoki mavjud shakl sinflarini o'zgartirmasdan.

**Eng yaxshi amaliyotlar**

- Sinflar yangi funksionallik bilan kengaytira oladigan moslashuvchan rejalar yaratish uchun mavhum sinflar yoki interfeyslarni kiriting. - Kichik sinflarga maxsus xatti-harakatlarni ta'minlash uchun metodlarni qayta belgilash imkonini bering. - Har xil sinflar ob'ektlarini umumiy interfeys orqali bir xilda ko'rib chiqish uchun polimorfizmdan foydalaning.

Class diagram showing Shape abstract class with Rectangle and Circle subclasses, demonstrating OCP
Ochiq/Yopiq Tamoyil (OCP)

Liskov Almashtirish Tamoyili (LSP)

Liskov Almashtirish Tamoyili (LSP) kelib chiqilgan sinf ob'ektlari dasturning to'g'riligiga ta'sir qilmasdan asosiy sinf ob'ektlarini almashtirishga qodir bo'lishi kerakligini bildiradi.

**LSP ni buzish**

Quyida barcha qushlar ucha oladi deb taxmin qilib LSP ni buzuvchi dizayn misoli:

```java class Bird { public void fly() { System.out.println("Osmonda uchmoqda."); } }

class Ostrich extends Bird { @Override public void fly() { throw new UnsupportedOperationException("Tuya tuyalar ucha olmaydi."); } }

// Dastur qush xatti-harakatini sinab ko'rish uchun bird.fly() ni chaqiradi ```

Ostrich sinfi Bird dan meros oladi, ammo tuya tuyalar ucha olmaganligi sababli `fly()` uchun istisno tashlaydi. Bu har qanday Bird uchil olishi mumkin degan kutishni buzadi va almashtirish tamoyilini buzadi.

**Buzilishni tuzatish**

Almashtirish imkoniyatini ta'minlash uchun ierarxiyani refaktorlang:

- Bird sinfini barcha qushlar bajara oladigan `move()` kabi yanada umumiy xatti-harakat bilan qayta aniqlang. - Bird sinfi har bir qush o'z qobiliyatlariga ko'ra amalga oshiradigan `move` metodini belgilaydi — Sparrow uchadi, Ostrich esa quruqlikda yuguradi.

**Eng yaxshi amaliyotlar**

- Kelib chiqilgan sinflar asosiy sinflarning xatti-harakat muvofiqligini saqlashini ta'minlang. - Metodlarni qayta belgilashda asosiy sinfning metod shartlarini (shartli shartlar, keyingi shartlar, invariantlar) hurmat qiling. - Kelib chiqilgan sinf ob'ektlari asosiy sinf ob'ektlarini almashtirishiga imkon berish uchun polimorfizmdan foydalaning.

Class diagram showing Bird abstract class with Sparrow and Ostrich subclasses, demonstrating LSP
Liskov Almashtirish Tamoyili (LSP)

Interfeys Ajratish Tamoyili (ISP)

Interfeys Ajratish Tamoyili (ISP) mijozlar o'zlari ishlatmaydigan interfeysalarga bog'liq bo'lishga majbur qilinmasligi kerakligini ta'kidlaydi. Interfeys amalga oshiruvchi sinflarga aloqador metodlarning aniq va maqsadli to'plamiga ega bo'lishi kerak.

**ISP ni buzish**

Quyida barcha amalga oshiruvchi sinflar ehtiyoj sezmaydigan metodlarni kiritish orqali ISP ni buzuvchi misol:

```java interface Worker { void work(); void eat(); void sleep(); }

class Robot implements Worker { public void work() { System.out.println("Payvandlash kabi vazifalarni bajarmoqda."); }

public void eat() { throw new UnsupportedOperationException("Robotlar ovqatlanmaydi."); }

public void sleep() { throw new UnsupportedOperationException("Robotlar uxlamaydi."); } }

class Human implements Worker { public void work() { System.out.println("Kodlash kabi vazifalarni bajarmoqda."); }

public void eat() { System.out.println("Ovqat yeymoqda."); }

public void sleep() { System.out.println("Dam olish uchun uxlamoqda."); } } ```

Worker interfeysi Robotni aloqasiz `eat` va `sleep` ni amalga oshirishga majbur qiladi, bu qo'llab-quvvatlanmaydigan operatsiyalarga olib keladi.

**Buzilishni tuzatish**

Maqsadli interfeysalarga bo'lish orqali refaktorlang:

- `Workable` — faqat `work` metodini o'z ichiga oladi, barcha ishchilarga qo'llaniladi. - `Eatable` — `eat` ni o'z ichiga oladi, odamlarga mos, robotlarga emas. - `Sleepable` — `sleep` ni o'z ichiga oladi, odamlarga xos.

Bu dizayn sinflarning faqat ehtiyojlari bo'lgan metodlarni amalga oshirishini ta'minlaydi.

**Eng yaxshi amaliyotlar**

- Interfeyslarni muayyan maqsad bilan, faqat shu maqsatga bevosita bog'liq metodlarni kiritgan holda loyihalang. - Sinflar amalga oshirishni tanlashi mumkin bo'lgan bir nechta kichik interfeyslar yarating. - Interfeysni amalga oshiruvchi sinflarning nuqtai nazaridan o'ylang.

Diagram showing Workable, Eatable, and Sleepable interfaces with Robot and Human implementing only relevant ones
Interfeys Ajratish Tamoyili (ISP)

Bog'liqliklarni Teskari Yo'naltirish Tamoyili (DIP)

Bog'liqliklarni Teskari Yo'naltirish Tamoyili (DIP) yuqori darajadagi modullar past darajadagi modullarga bog'liq bo'lmasligi kerakligini bildiradi; ikkalasi ham abstraksiyalarga bog'liq bo'lishi kerak. Bu yuqori darajadagi komponentlarni past darajadagi tafsilotlardan ajratish uchun mavhum interfeyslardan foydalanishni rag'batlantiradi.

**DIP ni buzish**

Quyida yuqori darajadagi sinf to'g'ridan-to'g'ri past darajadagi sinfga bog'liq bo'lish orqali DIP ni buzuvchi misol:

```java class LightBulb { public void turnOn() { System.out.println("Chiroq yondi."); }

public void turnOff() { System.out.println("Chiroq o'chdi."); } }

class Switch { private LightBulb bulb;

public Switch(LightBulb bulb) { this.bulb = bulb; }

public void operate() { bulb.turnOn(); } } ```

Switch sinfi to'g'ridan-to'g'ri past darajadagi LightBulb sinfiga bog'liq. Bu qattiq juftlashuv LightBulb ni o'zgartirish yoki uni boshqa qurilma bilan (Fan kabi) almashtirish Switch sinfini o'zgartirishni talab qilishini anglatadi.

**Buzilishni tuzatish**

Abstraksiyalardan foydalanish uchun refaktorlang:

- Standart metodlarni (`turnOn`, `turnOff`) belgilovchi `Switchable` interfeysini kiriting. - Switch sinfi faqat `Switchable` interfeysiga bog'liq bo'lishi uchun o'zgartiriladi. - `LightBulb` sinfi `Switchable` ni amalga oshiradi.

Endi Switch o'zgartirishlarsiz Switchable ni amalga oshirgan har qanday qurilma bilan (Fan, Heater) ishlashini amalga oshirishi mumkin.

**Eng yaxshi amaliyotlar**

- Yuqori darajadagi modullarga ushbu abstraksiyalarga bog'liq bo'lish imkonini beruvchi bog'liqliklarni ifodalash uchun interfeyslar yoki mavhum sinflarni kiriting. - Yuqori darajadagi modullarga ularning abstraksiyalari orqali konkret amalga oshirishlarni kiritish uchun bog'liqliklarni kiritishdan foydalaning. - Bu erkin juftlashuvni rag'batlantiradi va tizimni yanada moslashuvchan va kengaytirishga qulay qiladi.

Class diagram showing Switch depending on Switchable interface, with LightBulb and Fan as implementations
Bog'liqliklarni Teskari Yo'naltirish Tamoyili (DIP)

Xulosa

Bu bob Inkapsulyatsiya, Abstraksiya, Meros, Polimorfizm va SOLID tamoyillardan qanday foydalanishni tushunishga yordam berdi. Bu tushunchalar mustahkam dasturiy ta'minot dizaynining asosini tashkil etib, moslashuvchan, texnik xizmat ko'rsatish mumkin bo'lgan va miqyoslanadigan tizimlar yaratish imkonini beradi. Bu vositalardan foydalanish aniq dizayn qarorlarini ifodalashga, yondashuvingizni asoslashga va sanoat standarti amaliyotlarga rioyani namoyish etishga yordam beradi.

Ko'nikmalaringizni yanada oshirish va tajribangizni chuqurlashtirish uchun quyidagi manbalarga murojaat qiling:

- Robert C. Martinning *Toza Kod: Chaqqon Dasturiy Ta'minot Hunarmandchiligi Qo'llanmasi* - Erich Gamma, Richard Helm, Ralph Johnson va John Vlissides ning *Dizayn Naqshlari: Qayta Foydalanish Mumkin bo'lgan Ob'ektga Yo'naltirilgan Dasturiy Ta'minot Elementlari* - Kent Beckning *Avvalo Tartibga Keltirishmi?: Empirik Dasturiy Ta'minot Dizaynida Shaxsiy Mashq*

Bob 4

Avtoturargoh Loyihalash

~12 daq o'qish

Bu bobda biz Avtoturargoh tizimining ob'yektga yo'naltirilgan dizaynini o'rganamiz — texnik intervyulardagi eng mashhur savollardan biri. Ushbu avtoturargoh ilovasi avtoturargohni samarali boshqarish uchun keng qamrovli yechim taqdim etishni maqsad qiladi. U turli jarayonlarni avtomatlashtirib, shu jumladan transport vositasining kirishi, chiqishi va joy ajratishni, shuningdek avtoturargoh bandligi haqida to'liq ma'lumot taqdim etib, to'xtash chiptalarini chiqarishni ta'minlaydi.

Bu tizimni qurish uchun avval uning talablarini aniqlab olishimiz kerak.

Overview diagram of a parking lot system
Parking Lot

Talablarni Aniqlash

Avtoturargoh tizimini loyihalashning birinchi bosqichi — talablarni aniqlab, qamrovni belgilashdir. Mana intervyuer tomonidan odatda beriladigan savol namunasi:

> **Intervyuer:** "Tasavvur qiling: siz band avtoturargohdga yetib kelasiz va mashinangizni to'xtatmoqchi bo'lasiz. Kiraverishda sizga chipta beriladi. Keyin ichkariga kiriб, mashinangiz o'lchamiga mos joy topib, to'xtatib qo'yasiz. Ketmoqchi bo'lganingizda chiptangizni chiqish joyida ko'rsatasiz, tizim to'lov miqdorini hisoblab, joy yana keyingi transport vositasi uchun bo'shaydi. Sahna ortida avtoturargoh tizimi transport vositalari o'lchamiga qarab joylarni ajratadi, kirish va chiqish vaqtlarini qayd etadi va yangi kelganlar uchun bo'sh joylarni yangilab turadi. Endi barcha shu jarayonlarni boshqara oladigan avtoturargoh tizimini loyihalaylik."

---

> **Nomzod:** Avtoturargoh qanday turdagi transport vositalarini qo'llab-quvvatlaydi?

> **Intervyuer:** Uch turdagi transport vositasi qo'llab-quvvatlanishi kerak: mototsikllar, avtomobillar va yuk mashinalari.

> **Nomzod:** Avtoturargohdagi to'xtash joylari qanday turlarga bo'linadi?

> **Intervyuer:** Avtoturargoh uch turdagi joyni qo'llab-quvvatlaydi: kichik, oddiy va katta joylar.

> **Nomzod:** Tizim transport vositasiga qaysi joyni ajratishini qanday aniqlaydi?

> **Intervyuer:** Tizim transport vositasining o'lchamiga qarab mos joy ajratadi.

> **Nomzod:** Kiraverishda transport vositalariga chipta berilib, chiqishda to'lov undiriladi, shundaymi?

> **Intervyuer:** Ha, transport vositasi kirganda uning ma'lumotlari va kirish vaqti yozilgan chipta beriladi. Chiqishda tizim muddati va transport vositasining o'lchamiga qarab to'lov miqdorini hisoblaydi va joyni bo'sh deb belgilaydi.

> **Nomzod:** To'lov qanday hisoblanadi?

> **Intervyuer:** To'lov to'xtash muddati va transport vositasining o'lchamiga asoslanib, kunning vaqtiga qarab turli tariflar bo'yicha hisoblanadi.

**Talablar**

Biz aniqlab olgan asosiy funksional talablar:

- Avtoturargohda kichik, oddiy va katta turli to'xtash joylari mavjud. - Avtoturargoh mototsikllar, avtomobillar va yuk mashinalari uchun mo'ljallangan. - Mijozlar transport vositasi o'lchamiga qarab ajratilgan joylarga mashinalarini to'xtata oladi. - Mijozlar kirish joyida transport vositasi ma'lumotlari va kirish vaqti ko'rsatilgan chipta oladi; chiqishda muddati, transport vositasining o'lchami va kunning vaqtiga qarab to'lov to'laydi.

Funksional bo'lmagan talablar:

- Tizim juda ko'p joy va transport vositalariga ega katta avtoturargohlarni qo'llab-quvvatlash uchun kengaytirilishi mumkin bo'lishi kerak. - Tizim joy tayinlash va chipta tafsilotlarini ishonchli kuzatib, operatsiyalarning to'g'riligini ta'minlashi kerak.

Asosiy Ob'yektlarni Aniqlash

Dizaynga kirishdan oldin asosiy ob'yektlarni sanab chiqish muhim.

- **Vehicle (Transport vositasi):** Joyi kerak bo'lgan transport vositasini ifodalaydi. Davlat raqami va o'lchami (mototsikl uchun kichik, avtomobil uchun o'rta, yuk mashinasi uchun katta) kabi tafsilotlarni o'z ichiga oladi. - **ParkingSpot (To'xtash joyi):** Avtoturargohdagi alohida to'xtash joyini modellashtiradi; faqat o'lchamga mos transport vositalarining to'xtashini ta'minlaydi. - **Ticket (Chipta):** Transport vositasi kirganda beriladigan to'xtash chiptasini ifodalaydi. Chipta IDsi, bog'liq transport vositasi, ajratilgan ParkingSpot va kirish vaqtini saqlaydi. - **ParkingManager (Avtoturargoh menejer):** Joy ajratishni nazorat qiladi; ParkingSpot nusxalarini tayinlash, qidirish va bo'shatishni boshqaradi. - **ParkingLot (Avtoturargoh):** Fasad sifatida ishlaydi; transport vositasining kirishi, joy tayinlash, chiptalashtirish va to'lovni hisoblashni boshqarish uchun markaziy interfeys taqdim etadi.

> **Dizayn tanlovi:** Biz bu beshta ob'yektni javobgarliklarni ajratish maqsadida tanladik. Vehicle va ParkingSpot asosiy fizik ob'yektlarni belgilaydi, Ticket seanslarni kuzatadi, ParkingManager ajratishni boshqaradi, ParkingLot esa fasad sifatida koordinatsiya qiladi.

Sinflar Diagrammasini Loyihalash

Asosiy ob'yektlar va ularning vazifalarini aniqlaganimizdan so'ng, navbatdagi qadam avtoturargoh tizimini hayotga tatbiq etuvchi sinf va metodlarni loyihalashdir.

### Vehicle (Transport vositasi)

Biz Vehicle'ni barcha transport vositalari turlari uchun standart belgilaydigan interfeys sifatida modelladik. U ikkita asosiy metodini belgilaydi:

- `getLicensePlate()`: Transport vositasining davlat raqamini qaytaradi. - `getSize()`: U egallagan joyni ko'rsatadigan VehicleSize enum (SMALL, MEDIUM, LARGE) qaytaradi.

Konkret sinflar — Motorcycle, Car va Truck — Vehicle interfeysini amalga oshiradi, har biri o'z o'lchamini belgilaydi.

> **Dizayn tanlovi:** `getType()` o'rniga `getSize()` ishlatish aniq transport vositasi nomlarini abstrakt qiladi. Yuk mashinasi va minivan ikkalasi ham LARGE bo'lishi mumkin, shuning uchun to'xtash maqsadida ular bir xil ko'rib chiqiladi. Yangi transport vositasi turini qo'shish uchun faqat uning o'lchamini belgilash kerak — tizim sodda va moslashuvchan bo'lib qoladi.

UML class diagram showing Vehicle interface with Motorcycle, Car, and Truck implementations
Vehicle interface and its concrete classes

ParkingSpot Dizayni

ParkingSpot interfeysi to'xtash joyini ifodalaydi. Konkret sinflar (CompactSpot, RegularSpot, OversizedSpot) mos ravishda kichik, o'rta va katta transport vositalar uchun uni amalga oshiradi.

> **Dizayn tanlovi:** ParkingSpot ataylab sodda saqlangan — faqat o'z holatini (mavjudligi va o'lchami) boshqaradi. Bo'sh joylarni topish va to'xtatilgan transport vositalarini kuzatish kabi murakkab operatsiyalar ParkingManager'ga topshirilgan. Bu yangi joy turlarini keraksiz murakkabliksiz qo'shishni osonlashtiradi.

UML class diagram showing ParkingSpot interface with CompactSpot, RegularSpot, and OversizedSpot
ParkingSpot interface and its concrete classes

ParkingManager Dizayni

ParkingManager to'xtash joylarini ajratish va kuzatishni boshqaradi. Uning asosiy vazifalari:

- `parkVehicle(Vehicle vehicle)`: Transport vositasi kelganda uning o'lchamiga mos joy ajratadi. - `unparkVehicle(Vehicle vehicle)`: Transport vositasi ketganda joyni bo'shatadi.

> **Dizayn tanlovi:** ParkingManager joy ajratish va kuzatishni markazlashtiradi, bu ParkingLot'ning yengil fasad bo'lib qolishiga imkon beradi. Bu javobgarliklarni ajratish modullilik va kengaytirilishni yaxshilaydi.

UML class diagram of ParkingManager with its methods and associations
ParkingManager class

Ticket Dizayni

Ticket sinfi transport vositasi kirganda yaratilgan to'xtash chiptasini ifodalaydi. U muddat hisoblash uchun kirish/chiqish vaqtlarini kuzatadi va transport vositasini unga ajratilgan joy bilan bog'laydi.

> **Dizayn tanlovi:** Ticket to'xtash hodisasining ixcham, o'zgarmas yozuvi sifatida loyihalangan. Uning asosiy roli — ma'lumotlar konteynerи bo'lish; to'lov hisoblash kabi murakkab logika FareCalculator'ga topshirilgan.

UML class diagram of Ticket with ticketId, vehicle, parkingSpot, entryTime, and exitTime
Ticket class

FareStrategy va FareCalculator Dizayni

FareStrategy interfeysi to'lov miqdorini o'zgartirish uchun standart metod o'rnatadi. Konkret sinflar maxsus narxlash qoidalarini boshqaradi:

- **BaseFareStrategy:** Chipta muddati va transport vositasi o'lchamiga asoslanib asosiy to'lovni belgilaydi. - **PeakHoursFareStrategy:** Kunning vaqtiga qarab to'lovni o'zgartiradi (eng band soatlarda 50% yuqori).

FareCalculator yakuniy to'lovni hisoblash uchun bu strategiyalarni muvofiqlashtiradi. Narxlash logikasi **Strategy Pattern**'iga asoslanib, narxlash qoidalarini dinamik tanlash va almashtirish imkonini beradi.

> **Eslatma:** Strategy Pattern haqida ko'proq bilib olish uchun ushbu bobning oxiridagi Qo'shimcha O'qish bo'limiga murojaat qiling.

> **Dizayn tanlovi:** FareStrategy interfeysi modulli, almashinuvchan narxlash qoidalarini ta'minlaydi. FareCalculator'da `List<FareStrategy>` ishlatish strategiyalar tartibini saqlaydi — to'g'ri hisoblash uchun BaseFareStrategy PeakHoursFareStrategy'dan oldin bajarilishi shart.

UML class diagram showing FareStrategy interface with BaseFareStrategy and PeakHoursFareStrategy, coordinated by FareCalculator
FareStrategy interface and FareCalculator class

ParkingLot Dizayni

ParkingLot sinfi **fasad** sifatida ishlaydi, avtoturargohning asosiy operatsiyalarini boshqarish uchun oddiy interfeys taqdim etadi. U transport vositasining kirishi (chiptalar chiqarish, joylar ajratish) va chiqishini (to'lovlarni hisoblash) boshqaradi, ParkingManager va FareCalculator'ga topshiradi.

> **Eslatma:** Facade Pattern haqida ko'proq bilib olish uchun ushbu bobning oxiridagi Qo'shimcha O'qish bo'limiga murojaat qiling.

UML class diagram of ParkingLot showing its relationship to ParkingManager and FareCalculator
ParkingLot class (facade)

To'liq Sinflar Diagrammasi

To'liq sinf strukturasi va ular orasidagi munosabatlarni ko'rib chiqing. Bu diagramma bir qaraganda murakkab tuyuladigan tizimni bir-biri bilan uyg'un ishlayotgan oddiy, yaxshi loyihalangan komponentlar yordamida qanday qurish mumkinligini ko'rsatadi.

Full UML class diagram of the Parking Lot system showing all classes and their relationships
Complete Class Diagram of Parking Lot

Kod — Avtoturargoh

Bu bo'limda avtoturargoh tizimining asosiy funksiyalarini amalga oshiramiz.

### Vehicle (Transport vositasi)

Vehicle interfeysini, VehicleSize enum'ini va Car konkret sinfini aniqlaymiz:

```java public interface Vehicle { String getLicensePlate(); VehicleSize getSize(); }

public class Car implements Vehicle { private String licensePlate;

public Car(String licensePlate) { this.licensePlate = licensePlate; }

@Override public String getLicensePlate() { return this.licensePlate; }

@Override public VehicleSize getSize() { return VehicleSize.MEDIUM; } }

public enum VehicleSize { SMALL, MEDIUM, LARGE } ```

Interfeys har bir transport vositasining kuzatish uchun davlat raqamini va to'xtash joylarini boshqarish uchun o'lchamini taqdim etishini ta'minlaydi. Motorcycle va Truck sinflari Car bilan bir xil strukturani takrorlaydi.

> **Amalga oshirish tanlovi:** `VehicleSize` enum (SMALL, MEDIUM, LARGE) transport vositasi va to'xtash joyi o'lchamlarini standartlashtiradi, type-safe, xatosiz o'lcham taqqoslashlarini ta'minlaydi. Satrlar (yozuv xatolariga moyil) yoki butun sonlar (noaniq) kabi alternativlar mo'rtligi va type safety yo'qligi sababli rad etildi.

### ParkingSpot

```java public interface ParkingSpot { boolean isAvailable(); void occupy(Vehicle vehicle); void vacate(); int getSpotNumber(); VehicleSize getSize(); }

public class CompactSpot implements ParkingSpot { private int spotNumber; private Vehicle vehicle; // Hozirda bu joyda turgan transport vositasi

public CompactSpot(int spotNumber) { this.spotNumber = spotNumber; this.vehicle = null; // Dastlab transport vositasi yo'q }

@Override public int getSpotNumber() { return spotNumber; }

@Override public boolean isAvailable() { return vehicle == null; }

@Override public void occupy(Vehicle vehicle) { if (isAvailable()) { this.vehicle = vehicle; } else { // Joy allaqachon band. } }

@Override public void vacate() { this.vehicle = null; // Joyni bo'sh qilish }

@Override public VehicleSize getSize() { return VehicleSize.SMALL; // Kichik joylar kichik transport vositalariga mos } } ```

RegularSpot `VehicleSize.MEDIUM`, OversizedSpot esa `VehicleSize.LARGE` qaytaradi — har ikkalasi ham CompactSpot bilan bir xil strukturaga ega.

### ParkingManager

```java public class ParkingManager { private final Map<VehicleSize, List<ParkingSpot>> availableSpots; private final Map<Vehicle, ParkingSpot> vehicleToSpotMap;

// Mavjud joylar xaritasiga asoslanib ParkingManager yaratish public ParkingManager(Map<VehicleSize, List<ParkingSpot>> availableSpots) { this.availableSpots = availableSpots; this.vehicleToSpotMap = new HashMap<>(); }

public ParkingSpot findSpotForVehicle(Vehicle vehicle) { VehicleSize vehicleSize = vehicle.getSize();

// Transport vositasiga mos eng kichik joyni izlashni boshlash for (VehicleSize size : VehicleSize.values()) { if (size.ordinal() >= vehicleSize.ordinal()) { List<ParkingSpot> spots = availableSpots.get(size); for (ParkingSpot spot : spots) { if (spot.isAvailable()) { return spot; // Birinchi bo'sh joyni qaytarish } } } } return null; // Mos joy topilmadi }

public ParkingSpot parkVehicle(Vehicle vehicle) { ParkingSpot spot = findSpotForVehicle(vehicle); if (spot != null) { spot.occupy(vehicle); vehicleToSpotMap.put(vehicle, spot); availableSpots.get(spot.getSize()).remove(spot); return spot; // To'xtash muvaffaqiyatli } return null; // Bu transport vositasi uchun joy topilmadi }

public void unparkVehicle(Vehicle vehicle) { ParkingSpot spot = vehicleToSpotMap.remove(vehicle); if (spot != null) { spot.vacate(); availableSpots.get(spot.getSize()).add(spot); } } } ```

- `findSpotForVehicle()`: Transport vositasining o'lchamiga mos eng kichik bo'sh joyni qidiradi. - `parkVehicle()`: Joyni tayinlaydi, transport vositasi-joy juftligini qayd etadi, joyni mavjud havzadan chiqaradi. - `unparkVehicle()`: Joyni bo'shatadi, uni mavjud havzaga qaytaradi.

> **Amalga oshirish tanlovi:** Ikki HashMap O(1) kirish imkonini beradi: `availableSpots` joylarni VehicleSize bo'yicha eng yaxshi moslik uchun tartibga soladi; `vehicleToSpotMap` har bir transport vositasi qaysi joyda ekanligini qayd etadi.

### Ticket

```java public class Ticket { private final String ticketId; // Noyob chipta identifikatori private final Vehicle vehicle; // Chipta bilan bog'liq transport vositasi private final ParkingSpot parkingSpot; // Transport vositasi turgan to'xtash joyi private final LocalDateTime entryTime; // Transport vositasi avtoturargoхga kirgan vaqt private LocalDateTime exitTime; // Transport vositasi avtoturargohdan chiqqan vaqt

public Ticket( String ticketId, Vehicle vehicle, ParkingSpot parkingSpot, LocalDateTime entryTime) { this.ticketId = ticketId; this.vehicle = vehicle; this.parkingSpot = parkingSpot; this.entryTime = entryTime; this.exitTime = null; // Dastlab null — transport vositasi hali to'xtab turibdi }

public BigDecimal calculateParkingDuration() { return new BigDecimal( Duration.between( entryTime, Objects.requireNonNullElseGet(exitTime, LocalDateTime::now)) .toMinutes()); } // getter va setter metodlari qisqartirish uchun tushirib qoldirildi } ```

### FareStrategy va FareCalculator

```java public interface FareStrategy { BigDecimal calculateFare(Ticket ticket, BigDecimal inputFare); }

public class BaseFareStrategy implements FareStrategy { private static final BigDecimal SMALL_VEHICLE_RATE = new BigDecimal("1.0"); private static final BigDecimal MEDIUM_VEHICLE_RATE = new BigDecimal("2.0"); private static final BigDecimal LARGE_VEHICLE_RATE = new BigDecimal("3.0");

@Override public BigDecimal calculateFare(Ticket ticket, BigDecimal inputFare) { BigDecimal fare = inputFare; BigDecimal rate; switch (ticket.getVehicle().getSize()) { case MEDIUM: rate = MEDIUM_VEHICLE_RATE; break; case LARGE: rate = LARGE_VEHICLE_RATE; break; default: rate = SMALL_VEHICLE_RATE; } fare = fare.add(rate.multiply(ticket.calculateParkingDuration())); return fare; } }

public class PeakHoursFareStrategy implements FareStrategy { private static final BigDecimal PEAK_HOURS_MULTIPLIER = new BigDecimal("1.5"); // 50% yuqori

@Override public BigDecimal calculateFare(Ticket ticket, BigDecimal inputFare) { BigDecimal fare = inputFare; if (isPeakHours(ticket.getEntryTime())) { fare = fare.multiply(PEAK_HOURS_MULTIPLIER); } return fare; }

private boolean isPeakHours(LocalDateTime time) { int hour = time.getHour(); return (hour >= 7 && hour <= 10) || (hour >= 16 && hour <= 19); } }

public class FareCalculator { private final List<FareStrategy> fareStrategies;

public FareCalculator(List<FareStrategy> fareStrategies) { this.fareStrategies = fareStrategies; }

public BigDecimal calculateFare(Ticket ticket) { BigDecimal fare = BigDecimal.ZERO; for (FareStrategy strategy : fareStrategies) { fare = strategy.calculateFare(ticket, fare); } return fare; } } ```

> **Amalga oshirish tanlovi:** `FareCalculator` tartibni saqlash uchun `List<FareStrategy>` (Set yoki massiv emas) ishlatadi — BaseFareStrategy kabi strategiyalar to'g'ri to'lov hisoblash uchun PeakHoursFareStrategy'dan oldin bajarilishi shart.

### ParkingLot

```java public class ParkingLot { private final ParkingManager parkingManager; private final FareCalculator fareCalculator;

public ParkingLot(ParkingManager parkingManager, FareCalculator fareCalculator) { this.parkingManager = parkingManager; this.fareCalculator = fareCalculator; }

public Ticket enterVehicle(Vehicle vehicle) { ParkingSpot spot = parkingManager.parkVehicle(vehicle); if (spot != null) { Ticket ticket = new Ticket(generateTicketId(), vehicle, spot, LocalDateTime.now()); return ticket; } else { return null; // Bo'sh joy yo'q } }

public void leaveVehicle(Ticket ticket) { if (ticket != null && ticket.getExitTime() == null) { ticket.setExitTime(LocalDateTime.now()); parkingManager.unparkVehicle(ticket.getVehicle()); BigDecimal fare = fareCalculator.calculateFare(ticket); } else { // Noto'g'ri chipta yoki transport vositasi allaqachon chiqib ketgan. } } } ```

Chuqur O'rganish Mavzulari

### Yangi To'xtash Joyi Turini Qo'shish

Nogironlar uchun to'xtash joyini qo'shish uchun mavjud ParkingSpot interfeysini amalga oshiruvchi `HandicappedSpot` sinfini kiritamiz. Bu Ochiq-Yopiq Printsipiga amal qiladi — mavjud sinflarga o'zgartirish talab etilmaydi.

```java public class HandicappedSpot implements ParkingSpot { private int spotNumber; private Vehicle vehicle;

public HandicappedSpot(int spotNumber) { this.spotNumber = spotNumber; this.vehicle = null; }

@Override public int getSpotNumber() { return spotNumber; }

@Override public boolean isAvailable() { return vehicle == null; }

@Override public void occupy(Vehicle vehicle) { if (isAvailable()) { this.vehicle = vehicle; } }

@Override public void vacate() { this.vehicle = null; }

@Override public VehicleSize getSize() { return VehicleSize.MEDIUM; } } ```

### To'xtash Joyi Boshqaruvini Tezlashtirish

Joriy mapping bir tomonlama (Vehicle → ParkingSpot). Muayyan joyda qaysi transport vositasi turganini topish uchun barcha yozuvlarni ko'rib chiqish kerak — O(n). Har ikki yo'nalishda ham O(1) qidirish uchun teskari HashMap `spotToVehicleMap` qo'shsa bo'ladi:

```java public class ParkingManager { private final Map<VehicleSize, List<ParkingSpot>> availableSpots; private final Map<Vehicle, ParkingSpot> vehicleToSpotMap; private final Map<ParkingSpot, Vehicle> spotToVehicleMap;

public ParkingManager(Map<VehicleSize, List<ParkingSpot>> availableSpots) { this.availableSpots = availableSpots; this.vehicleToSpotMap = new HashMap<>(); this.spotToVehicleMap = new HashMap<>(); }

public ParkingSpot findSpotForVehicle(Vehicle vehicle) { // Metodda o'zgarish yo'q }

public ParkingSpot parkVehicle(Vehicle vehicle) { ParkingSpot spot = findSpotForVehicle(vehicle); if (spot != null) { spot.occupy(vehicle); vehicleToSpotMap.put(vehicle, spot); // Ikki tomonlama mappingni qayd etish spotToVehicleMap.put(spot, vehicle); availableSpots.get(spot.getSize()).remove(spot); return spot; } return null; }

public void unparkVehicle(Vehicle vehicle) { ParkingSpot spot = vehicleToSpotMap.remove(vehicle); if (spot != null) { spotToVehicleMap.remove(spot); spot.vacate(); availableSpots.get(spot.getSize()).add(spot); } }

public ParkingSpot findVehicleBySpot(Vehicle vehicle) { return vehicleToSpotMap.get(vehicle); }

public Vehicle findSpotByVehicle(ParkingSpot spot) { return spotToVehicleMap.get(spot); } } ```

**Afzalliklari:** Ikki tomonlama mapping har ikki yo'nalishda ham O(1) qidirish imkonini beradi — ayniqsa chiziqli qidirish qimmatga tushadigan katta avtoturargohlar uchun samarali.

UML class diagram showing HandicappedSpot added to the ParkingSpot hierarchy
ParkingSpot with HandicappedSpot extension

Xulosa

Bu bobda biz Avtoturargoh tizimi uchun talablarni to'pladik, asosiy ob'yektlarni aniqladik, sinf strukturasini loyihaladik va asosiy komponentlarni amalga oshirdik.

Asosiy o'rganish — modullilik va aniq javobgarliklarni ajratishning qiymati. Har bir komponent alohida javobgarlikni bajaradi, bu tizimni qo'llab-quvvatlash va kelajakdagi takomillashtirishlar uchun ochiq holda saqlaydi.

Dizayn tanlovlarimiz — ParkingLot'ni fasad sifatida ishlatish, FareStrategy'ni moslashuvchan narxlash uchun qo'llash — soddalik va moslashuvchanlikni ta'kidlaydi. Joy ajratish va to'lov logikasini to'g'ridan-to'g'ri ParkingLot'ga joylashtiruvchi alternativ yondashuv sinf sonini kamaytirishi mumkin, lekin bir sinfni bir nechta javobgarlik bilan yuklab, kengaytirilishni murakkablashtiradi.

Qo'shimcha O'qish: Strategy va Facade Dizayn Naqshlari

### Strategy Dizayn Naqshi

Strategy naqshi algoritmlar oilasini aniqlaydi, har birini alohida sinfda inkapsuliyalaydi va ularning ob'yektlarini almashinuvchan qiladi.

**Qachon ishlatish kerak:** - Ilova muayyan shartlarga qarab ish vaqtida turli algoritmlarni tanlashi kerak bo'lganda. - Sinf algoritm variantlari orasida tanlov qiluvchi shartli ifodalar bilan to'lib-toshganda. - Biznes logikasini muayyan vazifalarning amalga oshirish tafsilotlaridan alohida saqlash uchun.

**Misol:** Kredit karta, PayPal va bank o'tkazmasi imkoniyatlariga ega elektron tijorat to'lov tizimi — har bir to'lov usuli strategiya bo'lib, checkout asosiy logikasini o'zgartirmasdan almashinuvchandir.

### Facade Dizayn Naqshi

Facade naqshi murakkab quyi tizimga oddiy interfeys taqdim etib, mijozlarning u bilan o'zaro ta'sirini asosiy murakkablikni yashirish orqali soddalashtiradi.

**Qachon ishlatish kerak:** - Quyi tizim murakkab bo'lib, soddaroq mijoz interfeysi kerak bo'lganda. - Tizimni umumiy operatsiyalar uchun yagona kirish nuqtasi bilan quyi tizimlarga bo'lmoqchi bo'lganda.

**Misol:** Uy kinoteatr tizimi — `HomeTheaterFacade.watchMovie()` metodi projektor, ovoz tizimi va chiroqlarni ichki boshqaradi, foydalanuvchi har bir qurilmani sozlash o'rniga bitta oddiy chaqiruv orqali muloqot qiladi.

UML class diagram illustrating the Strategy design pattern with a PaymentStrategy example
Strategy design pattern class diagram
UML class diagram illustrating the Facade design pattern with a HomeTheater example
Facade design pattern class diagram
Bob 5

Kino Chipta Bron Qilish Tizimini Loyihalash

~13 daq o'qish

Bu bobda biz Kino Chipta Bron Qilish Tizimining dizaynini bosqichma-bosqich ko'rib chiqamiz. Bu tizim real dunyodagi tizimlarni modellashtirish va ob'yektga yo'naltirilgan printsiplarni yaxshi tuzilgan yechim yaratish uchun qo'llash qobiliyatingizni baholashda ishlatiladi. Maqsad — zal, seans va filmlar kabi kino bron tizimidagi asosiy sub'yektlarni ifodalaydigan sinflarni aniq belgilashdir. Biz ushbu komponentlar o'rtasidagi muhim o'zaro ta'sirlarni o'zida aks ettiruvchi aniq va funksional strukturani qurishga harakat qilamiz, bu tizimni intuitiv va kengaytirilishi mumkin qiladi.

Overview illustration of a movie theater booking system
Movie Theater

Talablarni Aniqlash

Mana intervyuer tomonidan odatda beriladigan savol namunasi:

> **Intervyuer:** "Tasavvur qiling: band dam olish kunida mashhur film uchun chipta bronlashga harakat qilyapsiz. Bron tizimiga kirasiz, mavjud seans vaqtlarini ko'rib chiqasiz, yoqtirgan o'rningizni tanlab, bronlaysiz. Bir zumda chiptalaringiz tasdiqlangan va sizga raqamli chipta yuboriladi. Sahna ortida tizim o'rinlarning mavjudligini samarali boshqaradi, seanslarni kuzatadi va chipta narxlarini hisoblab chiqadi. Endi barcha shu jarayonlarni uzluksiz boshqaruvchi kino chipta bron tizimini loyihalaylik."

---

> **Nomzod:** Tizim turli kinoteatlrlar va zallar bo'yicha chiptalarni topish va bronlashni qo'llab-quvvatlaydimi?

> **Intervyuer:** Ha, foydalanuvchilar bir nechta kinoteatlrlar bo'yicha mavjud chiptalarni qidirishlari mumkin, har bir kinoteatlrda bir nechta zal mavjud.

> **Nomzod:** Tizim bir xil filmning turli zal va vaqtlarda bir nechta seansini rejalashtirish imkonini beradimi?

> **Intervyuer:** Ha, har bir film bir xil yoki turli kinoteatlrdagi turli zal va vaqtlarda rejalashtirilgan bir nechta seansga ega bo'lishi mumkin.

> **Nomzod:** Tizim bir xil seansda o'rindiqlar uchun turli narx darajalarini qo'llab-quvvatlaydimi?

> **Intervyuer:** Ha, har bir o'rindiqning narx strategiyasi bo'lishi mumkin, masalan, oddiy, premium yoki VIP, bu chipta narxiga ta'sir qiladi.

> **Nomzod:** Foydalanuvchi bitta buyurtmada bir nechta chipta bron qila oladimi va tizim umumiy narxni qanday hisoblaydi?

> **Intervyuer:** Ha, foydalanuvchilar muayyan seans uchun bir nechta chiptani bitta buyurtmaga birlashtirishlari mumkin. Tizim tanlangan barcha o'rindiqlarning narx sinflariga asoslanib narxlarini qo'shib umumiy narxni hisoblaydi.

> **Nomzod:** Tizim bron jarayonining bir qismi sifatida to'lovni qayta ishlashni hal qiladimi?

> **Intervyuer:** Bu dizayn uchun to'lovni qayta ishlashni e'tiborsiz qoldirib, ko'rish, rejalashtirish, o'rin tanlash va chipta bronlashga e'tibor qarataylik.

> **Nomzod:** Foydalanuvchi muayyan o'rin uchun chipta bronlaganda nima bo'ladi?

> **Intervyuer:** Tizim seans, o'rin va o'rindiqning narx strategiyasiga asoslanib narx ko'rsatilgan chipta yaratishi, keyin uni seansning chipta ro'yxatiga qo'shib, o'rindiqni band deb belgilashi kerak.

**Talablar**

Funksional talablar:

- Har bir kinoteatlr ma'lum manzilda joylashgan va bir nechta zaldan iborat. - Filmlar turli zal, kinoteatlr va vaqt oraliqlarida rejalashtirilgan bir nechta seansga ega bo'lishi mumkin. - Har bir zalda bronlash uchun mavjud o'rindiqlar to'ri mavjud. - Zaldagi o'rindiqlar chipta narxlariga ta'sir qiluvchi turli narx strategiyalariga (oddiy, premium, VIP) ega bo'lishi mumkin. - Foydalanuvchilar mavjud chiptalarni topib, bronlay olishadi. - Chipta muayyan vaqtda muayyan zalda film tomosha qilish uchun aniq o'rindiqni anglatadi. - Foydalanuvchi bitta buyurtma doirasida bir nechta chipta bron qila oladi. - Buyurtma uchun umumiy narx tanlangan barcha o'rindiqlar narxlarini qo'shish orqali hisoblanadi.

Funksional bo'lmagan talablar:

- Silliq foydalanuvchi tajribasi uchun seanslarni tez qidirish. - Bir xil o'rindiqni ikki marta bronlash kabi bron konfliktlarining oldini oluvchi asosiy xato boshqaruvi.

Asosiy Ob'yektlarni Aniqlash

Modulli va qo'llab-quvvatlash mumkin bo'lgan tizim qurish uchun aniq javobgarliklariga ega alohida sub'yektlarni ifodalaydigan ob'yektlarni aniqlaymiz:

- **Movie (Film):** Kinoteatlrlarda ko'rsatiladigan muayyan filmni ifodalaydi, uning sarlavhasi va davomiyligi kabi muhim tafsilotlarini o'zida saqlaydi. - **Cinema (Kinoteatlr):** Bir nechta zaldan iborat, filmlar namoyish etiladigan fizik manzilni modellashtiradi. - **Room (Zal):** Kinoteatlr ichidagi namoyish makonini belgilaydi, o'rindiqlarning noyob joylanishiga bog'langan. - **Layout (Joylashuv):** Zalning o'tirish tartibini to'r sifatida tashkil etadi, o'rin pozitsiyalarini boshqaradi. - **Seat (O'rindiq):** Narx strategiyasiga bog'langan zaldagi alohida o'rindiqni ifodalaydi. - **Screening (Seans):** Film, zal va vaqt oralig'ini birlashtirib, filmning qachon va qayerda ko'rsatilishini belgilaydi. - **Ticket (Chipta):** Seans uchun muayyan o'rindiq tanlovini narxi bilan birga qayd etadi. - **Order (Buyurtma):** Bir tranzaksiyada birgalikda sotib olingan bir nechta chiptani guruhlaydi, umumiy narxni kuzatadi.

> **Dizayn tanlovi:** Doimiy film ma'lumotlarini dinamik seans jadvallaridan ajratish uchun Movie va Screening'ni ajratamiz. Room'ni Layout'dan ajratish zallarga umumiy yoki maxsus o'tirish tartibini qo'llash imkonini beradi. Room va Layout'ni birlashtirish mumkin, lekin bu zallar turli tartiblarga muhtoj bo'lganda moslashuvchanlikni cheklaydi.

> **Intervyu maslahat:** Ob'yektlarni intervyuda taqdim etayotganda ularni nega tanlaganingiz va talablarni qanday qondirganini tushuntiring. Turli variantlarni ko'rib chiqqaningizni ko'rsatish uchun alternativlarni ham aytib o'ting.

Sinflar Diagrammasini Loyihalash

### Movie (Film)

Movie sinfi muayyan film haqidagi muhim tafsilotlarni — sarlavha, janr va davomiylikni — o'zida saqlaydi; bu ma'lumotlar barcha seanslarda o'zgarmas qoladi. U seansdan ajralib turadi, chunki seans filmni zal va vaqt oralig'iga bog'laydi.

> **Dizayn tanlovi:** Movie kinoteatlrga xos yoki rejalashtirish kontekstlaridan mustaqil, alohida sub'yekt sifatida loyihalangan. Bu bir xil Movie'ni ma'lumotlar takrorlanishisiz bir nechta kinoteatlr va seanslarda qayta ishlatish imkonini beradi.

UML class diagram for the Movie class with title, genre, and durationInMinutes attributes
Movie class

Seat va PricingStrategy Dizayni

Seat sinfi alohida o'rindiq haqida asosiy tafsilotlarni, shu jumladan uning noyob raqamini saqlaydi. U NormalRate, PremiumRate va VIPRate konkret sinflari bilan PricingStrategy interfeysi orqali **Strategy Pattern**'idan foydalanadi.

Strategy naqshi tizimga quyidagi foyda keltiradi: - Kengaytirilishni oshiradi — yangi narx sinflarini qo'shish oson. - Kodni takrorlashni kamaytiradi — bitta Seat sinfi barcha narxlash variantlarini boshqaradi.

> **Muqobil yondashuv:** Narxlash logikasini to'g'ridan-to'g'ri Seat'ga joylashtirish narxlash qoidalari o'zgarganda moslashuvchanlikni kamaytiradi. Strategy naqshi, garchi murakkabrok bo'lsa ham, kelajakdagi kengaytirishlarni qo'llab-quvvatlaydi.

> **Eslatma:** Strategy naqshi haqida ko'proq bilib olish uchun Avtoturargoh bobiga murojaat qiling.

UML class diagram showing Seat class with PricingStrategy interface and NormalRate, PremiumRate, VIPRate implementations
Seat and PricingStrategy design

Layout Dizayni

Layout sinfi o'rindiqlarni qator va ustunlar bilan belgilangan to'r strukturasiga tashkil etadi. Quyidagilardan foydalanadi: - Pozitsiya bo'yicha samarali qidirish uchun ichma-ich map `Map<Integer, Map<Integer, Seat>>` (qator → ustun → o'rindiq). - O'rindiq raqami bo'yicha O(1) qidirish uchun alohida indeks `Map<String, Seat>`.

> **Muqobil yondashuv:** 2D massiv qat'iy o'lchamli zallar uchun ishlashi mumkin, lekin tartibsiz joylanishlar yoki dinamik o'rindiq qo'shishlar uchun moslashuvchanlikdan mahrum. Ichma-ich map `computeIfAbsent` yordamida dinamik qator yaratishni qo'llab-quvvatlaydi.

> **Intervyu maslahat:** Kod yozayotganda ma'lumotlar strukturasini (masalan, map vs massiv) nega tanlaganingiz va u dizayn maqsadlaringizni qanday qo'llashini tushuntiring.

UML class diagram for Layout showing nested map structure for seat management
Layout class

Cinema va Room Dizayni

Cinema bir nechta Room nusxasini o'z ichiga oladi (kompozitsiya). Har bir Room o'tirish tartibini belgilash uchun Layout'ni o'z ichiga oladi. Ular birgalikda teatr makonlarini boshqarish uchun aniq ierarxiya hosil qiladi.

> **Dizayn tanlovi:** Cinema va Room o'rtasidagi kompozitsion munosabat har bir Room'ning o'z tartibi va jadvali bilan mustaqil ishlashiga imkon beradi, Cinema esa yagona kontekst taqdim etadi.

UML class diagram showing Cinema containing multiple Rooms, each with a Layout
Cinema and Room classes

Screening Dizayni

Screening sinfi muayyan vaqtda muayyan zalda filmning ko'rsatilishini belgilaydi. U Movie, Room va vaqt tafsilotlarini bitta sub'yektga birlashtiradi.

> **Dizayn tanlovi:** Screening rejalashtirish tafsilotlarini markazlashtiradi, bu kinoteatlrlar bo'yicha seans vaqtlarini boshqarishni osonlashtiradi va javobgarliklarni aniq ajratishni ta'minlaydi.

UML class diagram for Screening with movie, room, startTime, and endTime
Screening class

Ticket va Order Dizayni

**Ticket** sinfi muayyan Screening uchun sotib olingan o'rindiqni ifodalaydi. U sotib olish vaqtidagi o'rindiq narxini o'zida saqlaydi — bu chipta narxi kelajakda o'rindiqning narx strategiyasi o'zgarishidan qat'i nazar, o'zgarmas bo'lib qolishini ta'minlaydi.

**Order** sinfi bir nechta chiptani bitta tranzaksiyaga guruhlaydi, buyurtma vaqt belgiasini qayd etadi va umumiy narxni taqdim etadi.

UML class diagram for Ticket with screening, seat, and price
Ticket class
UML class diagram for Order with tickets list and orderDate
Order class

ScreeningManager va MovieBookingSystem Dizayni

**ScreeningManager** seanslar va chiptalar uchun markazlashtirilgan menejerdir. U filmlar va ularning seanslari, shuningdek seanslar va ularning chiptlari orasidagi mappinglarni saqlaydi.

> **Dizayn tanlovi:** Muqobil yondashuv — bu operatsiyalarni Cinema sinfiga joylashtirish, lekin bu statik kinoteatlr atributlarini rejalashtirish/bron logikasi bilan bog'lab, modulliligi pasaytiradi.

**MovieBookingSystem** **fasad** sifatida ishlaydi, filmlar, kinoteatlr manzillari va ScreeningManager'ni yaxlit tizimga birlashtiradi. U asosiy operatsiyalarni markazlashtiradi — filmlarni qo'shish, seanslarni topish, o'rin mavjudligini tekshirish va chiptalarni bronlash.

> **Muqobil yondashuv:** Mijoz kodining ScreeningManager yoki Cinema bilan to'g'ridan-to'g'ri muloqot qilishiga ruxsat berish bog'liqlikni va mo'rtlikni oshiradi. Facade naqshi qo'llab-quvvatlash imkoniyatini yaxshilaydi.

UML class diagram for ScreeningManager with movie-screening and screening-ticket mappings
ScreeningManager class
UML class diagram for MovieBookingSystem showing its delegating relationship to ScreeningManager
MovieBookingSystem class (facade)

To'liq Sinflar Diagrammasi

Quyida kino chipta bron qilish tizimining to'liq sinflар diagrammasi keltirilgan.

Full UML class diagram showing all classes and their relationships in the movie ticket booking system
Complete Class Diagram of Movie Ticket Booking System

Kod — Kino Chipta Bron Qilish Tizimi

### Movie (Film)

```java public class Movie { private final String title; private final String genre; private final int durationInMinutes;

public Movie(String title, String genre, int durationInMinutes) { this.title = title; this.genre = genre; this.durationInMinutes = durationInMinutes; }

public Duration getDuration() { return Duration.ofMinutes(durationInMinutes); } // getter metodlari qisqartirish uchun tushirib qoldirildi } ```

`getDuration()` metodi `durationInMinutes`'ni Duration ob'yektiga aylantiradi, filmning davomiyligini standart tarzda ifodalaydi. Sinf o'zgarmas — setter metodlari yo'q — bu film tafsilotlarining yaratilgandan keyin o'zgarmasligini ta'minlaydi.

### Cinema (Kinoteatlr)

```java public class Cinema { private final String name; private final String location; private final List<Room> rooms;

public Cinema(String name, String location) { this.name = name; this.location = location; this.rooms = new ArrayList<>(); }

public void addRoom(Room room) { rooms.add(room); } // getter va setter metodlari qisqartirish uchun tushirib qoldirildi } ```

### Room (Zal)

```java public class Room { private final String roomNumber; private final Layout layout;

public Room(String roomNumber, Layout layout) { this.roomNumber = roomNumber; this.layout = layout; } // getter va setter metodlari qisqartirish uchun tushirib qoldirildi } ```

### Layout (Joylashuv)

```java // Kino zalining o'tirish tartibini ifodalaydi. public class Layout { private final int rows; private final int columns; // To'g'ridan-to'g'ri kirish uchun o'rindiq raqamlarini (masalan, "0-0") Seat ob'yektlariga aylantiradi private final Map<String, Seat> seatsByNumber; // Pozitsiyaga asoslangan kirish uchun ichma-ich map (qator → ustun → o'rindiq) private final Map<Integer, Map<Integer, Seat>> seatsByPosition;

public Layout(int rows, int columns) { this.rows = rows; this.columns = columns; this.seatsByNumber = new HashMap<>(); this.seatsByPosition = new HashMap<>(); initializeLayout(); }

private void initializeLayout() { for (int i = 0; i < rows; i++) { for (int j = 0; j < columns; j++) { String seatNumber = i + "-" + j; addSeat(seatNumber, i, j, new Seat(seatNumber, null)); } } }

public void addSeat(String seatNumber, int row, int column, Seat seat) { seatsByNumber.put(seatNumber, seat); seatsByPosition.computeIfAbsent(row, k -> new HashMap<>()).put(column, seat); }

public Seat getSeatByNumber(String seatNumber) { return seatsByNumber.get(seatNumber); }

public Seat getSeatByPosition(int row, int column) { Map<Integer, Seat> rowSeats = seatsByPosition.get(row); return (rowSeats != null) ? rowSeats.get(column) : null; }

public List<Seat> getAllSeats() { return List.copyOf(seatsByNumber.values()); } } ```

- `addSeat()` ichma-ich mapda qatorlarni dinamik yaratish uchun `computeIfAbsent` ishlatadi. - `getSeatByNumber()` o'rindiq identifikatori bo'yicha O(1) qidirish imkonini beradi. - `getSeatByPosition()` qator va ustun koordinatalari bo'yicha o'rindiqlarni oladi. - `getAllSeats()` xavfsiz kirish uchun o'zgarmas ro'yxat qaytaradi.

> **Amalga oshirish tanlovi:** To'r uchun ichma-ich `Map<Integer, Map<Integer, Seat>>` O(1) kirish va dinamik qator yaratishni qo'llab-quvvatlaydi. 2D massiv qat'iy tartiblar uchun soddaroq, lekin tartibsiz to'rlar uchun moslashuvchan emas.

### Seat (O'rindiq)

```java public class Seat { private final String seatNumber; private PricingStrategy pricingStrategy;

public Seat(String seatNumber, PricingStrategy pricingStrategy) { this.seatNumber = seatNumber; this.pricingStrategy = pricingStrategy; } // getter va setter metodlari qisqartirish uchun tushirib qoldirildi } ```

### PricingStrategy (Narxlash Strategiyasi)

```java public interface PricingStrategy { BigDecimal getPrice(); }

public class NormalRate implements PricingStrategy { private final BigDecimal price;

public NormalRate(BigDecimal price) { this.price = price; }

@Override public BigDecimal getPrice() { return price; } }

public class PremiumRate implements PricingStrategy { private final BigDecimal price;

public PremiumRate(BigDecimal price) { this.price = price; }

@Override public BigDecimal getPrice() { return price; } }

public class VIPRate implements PricingStrategy { private final BigDecimal price;

public VIPRate(BigDecimal price) { this.price = price; }

@Override public BigDecimal getPrice() { return price; } } ```

Yangi narxlash strategiyalari mavjud kodni o'zgartirmasdan qo'shilishi mumkin — Ochiq-Yopiq Printsipiga amal qiladi.

### Screening (Seans)

```java // Muayyan kino zalida rejalashtirilgan film seansini ifodalaydi. public class Screening { private final Movie movie; private final Room room; private final LocalDateTime startTime; private final LocalDateTime endTime;

public Screening(Movie movie, Room room, LocalDateTime startTime, LocalDateTime endTime) { this.movie = movie; this.room = room; this.startTime = startTime; this.endTime = endTime; }

public Duration getDuration() { return Duration.between(startTime, endTime); } // getter va setter metodlari qisqartirish uchun tushirib qoldirildi } ```

### Ticket (Chipta)

```java public class Ticket { private final Screening screening; private final Seat seat; private final BigDecimal price;

public Ticket(Screening screening, Seat seat, BigDecimal price) { this.screening = screening; this.seat = seat; this.price = price; } // getter va setter metodlari qisqartirish uchun tushirib qoldirildi } ```

### Order (Buyurtma)

```java public class Order { private final List<Ticket> tickets; private final LocalDateTime orderDate;

public Order(LocalDateTime orderDate) { this.tickets = new ArrayList<>(); this.orderDate = orderDate; }

public void addTicket(Ticket ticket) { tickets.add(ticket); }

public BigDecimal calculateTotalPrice() { return tickets.stream() .map(Ticket::getPrice) .reduce(BigDecimal.ZERO, BigDecimal::add); } // getter va setter metodlari qisqartirish uchun tushirib qoldirildi } ```

### ScreeningManager

```java // Filmlar, seanslar va chiptalar orasidagi munosabatlarni boshqaradi public class ScreeningManager { private final Map<Movie, List<Screening>> screeningsByMovie; private final Map<Screening, List<Ticket>> ticketsByScreening;

public ScreeningManager() { this.screeningsByMovie = new HashMap<>(); this.ticketsByScreening = new HashMap<>(); }

public void addScreening(Movie movie, Screening screening) { screeningsByMovie.computeIfAbsent(movie, k -> new ArrayList<>()).add(screening); }

public List<Screening> getScreeningsForMovie(Movie movie) { return screeningsByMovie.getOrDefault(movie, new ArrayList<>()); }

public void addTicket(Screening screening, Ticket ticket) { ticketsByScreening.computeIfAbsent(screening, k -> new ArrayList<>()).add(ticket); }

public List<Ticket> getTicketsForScreening(Screening screening) { return ticketsByScreening.getOrDefault(screening, new ArrayList<>()); }

public List<Seat> getAvailableSeats(Screening screening) { List<Seat> allSeats = screening.getRoom().getLayout().getAllSeats(); List<Ticket> bookedTickets = getTicketsForScreening(screening);

List<Seat> availableSeats = new ArrayList<>(allSeats); for (Ticket ticket : bookedTickets) { availableSeats.remove(ticket.getSeat()); } return availableSeats; } } ```

`getAvailableSeats()` zal tartibidan barcha o'rindiqlarni olib, seans uchun allaqachon chipta bilan bog'langan o'rindiqlarni o'chirib tashlaydi.

> **Amalga oshirish tanlovi:** `Map<Movie, List<Screening>>` va `Map<Screening, List<Ticket>>` O(1) qidirish imkonini beradi. Qo'lda filtrlashli tekis List O(n) bo'lar edi.

### MovieBookingSystem

```java // To'liq kino bron tizimi operatsiyalarini boshqaradi public class MovieBookingSystem { private final List<Movie> movies; private final List<Cinema> cinemas; private final ScreeningManager screeningManager;

public MovieBookingSystem() { this.movies = new ArrayList<>(); this.cinemas = new ArrayList<>(); this.screeningManager = new ScreeningManager(); }

public void addMovie(Movie movie) { movies.add(movie); }

public void addCinema(Cinema cinema) { cinemas.add(cinema); }

public void addScreening(Movie movie, Screening screening) { screeningManager.addScreening(movie, screening); }

public void bookTicket(Screening screening, Seat seat) { BigDecimal price = seat.getPricingStrategy().getPrice(); Ticket ticket = new Ticket(screening, seat, price); screeningManager.addTicket(screening, ticket); }

public List<Screening> getScreeningsForMovie(Movie movie) { return screeningManager.getScreeningsForMovie(movie); }

public List<Seat> getAvailableSeats(Screening screening) { return screeningManager.getAvailableSeats(screening); }

public int getTicketCount(Screening screening) { return screeningManager.getTicketsForScreening(screening).size(); }

public List<Ticket> getTicketsForScreening(Screening screening) { return screeningManager.getTicketsForScreening(screening); } // getter va setter metodlari qisqartirish uchun tushirib qoldirildi } ```

Chuqur O'rganish Mavzulari

### Parallel Bronlashlarni Boshqarish

OOD intervyularida bir vaqtning o'zida bir nechta foydalanuvchi muloqot qiladigan kino chipta bron qilish kabi tizimlar uchun parallellik ko'pincha muhokama qilinadi. Intervyuerdan parallellikni boshqarish zarurligini doimo so'rang.

**Muammo: Race Condition** — Ikki foydalanuvchi bir vaqtda bir xil o'rindiq uchun bron qilishga urinadi, bu ikki marta bronlashga olib kelishi mumkin.

**Yechim: Pessimistik vs Optimistik Blokirovka**

**Pessimistik Blokirovka** bron jarayonining boshida o'rindiqqa eksklyuziv qulf qo'yib, qo'yib yuborilmaguncha parallel kirishni oldini oladi. Vaqt tugash mexanizmi (masalan, 30 sekund) tranzaksiya tugallanmasa qulfni avtomatik ravishda bo'shatadi. Yuqori raqobat stsenariylar uchun eng yaxshi.

```java public class SeatLockManager { private final Map<String, SeatLock> lockedSeats = new ConcurrentHashMap<>(); private final Duration lockDuration;

public SeatLockManager(Duration lockDuration) { this.lockDuration = lockDuration; }

public synchronized boolean lockSeat(Screening screening, Seat seat, String userId) { String lockKey = generateLockKey(screening, seat); cleanupLockIfExpired(lockKey); if (isLocked(screening, seat)) { return false; } SeatLock lock = new SeatLock(userId, LocalDateTime.now().plus(lockDuration)); lockedSeats.put(lockKey, lock); return true; }

public synchronized boolean isLocked(Screening screening, Seat seat) { String lockKey = generateLockKey(screening, seat); cleanupLockIfExpired(lockKey); return lockedSeats.containsKey(lockKey); }

private void cleanupLockIfExpired(String lockKey) { SeatLock lock = lockedSeats.get(lockKey); if (lock != null && lock.isExpired()) { lockedSeats.remove(lockKey); } }

private String generateLockKey(Screening screening, Seat seat) { return screening.getId() + "-" + seat.getSeatNumber(); }

private static class SeatLock { private final String userId; private final LocalDateTime expirationTime;

public SeatLock(String userId, LocalDateTime expirationTime) { this.userId = userId; this.expirationTime = expirationTime; }

public boolean isExpired() { return LocalDateTime.now().isAfter(expirationTime); }

public String getUserId() { return userId; } } } ```

**Optimistik Blokirovka** bron paytida o'rindiqlarni qulflashdan qochib, o'rning mavjudligini oxirgi bosqichda tekshiradi. Agar boshqa foydalanuvchi oraliq vaqtda o'rindiqni bronlagan bo'lsa, tranzaksiya muvaffaqiyatsiz bo'ladi va foydalanuvchi qayta urinadi. Past raqobat stsenariylar uchun eng yaxshi.

```java // ScreeningManager'da soddalashtirilgan optimistik blokirovka public synchronized Ticket bookSeatOptimistically(Screening screening, Seat seat) { // O'rindiq mavjudligini tekshirish (optimistik — doimiy qulf saqlanmaydi) if (isSeatBooked(screening, seat)) { throw new IllegalStateException("O'rindiq allaqachon bronlangan"); }

BigDecimal price = seat.getPricingStrategy().getPrice(); Ticket ticket = new Ticket(screening, seat, price);

// Atomik tarzda bron tizimiga qo'shish — aslida o'rindiqni "zahiralaydi" ticketsByScreening.computeIfAbsent(screening, k -> new ArrayList<>()).add(ticket);

return ticket; }

private boolean isSeatBooked(Screening screening, Seat seat) { List<Ticket> tickets = getTicketsForScreening(screening); return tickets.stream().anyMatch(ticket -> ticket.getSeat().equals(seat)); } ```

> **Intervyu maslahat:** Pessimistik blokirovka yuqori raqobatli mashhur seanslar uchun ko'pincha afzal, optimistik blokirovka esa kamroq konfliktli oddiyroq holatlarga mos. Intervyuerdan qaysi yondashuv ularning kutganlariga mos kelishini so'rang.

Xulosa

Bu bobda biz Kino Chipta Bron Qilish Tizimi uchun talablarni to'pladik, asosiy ob'yektlarni aniqladik, sinf strukturasini loyihaladik va asosiy komponentlarni amalga oshirdik.

Asosiy o'rganish — modullilik va Yagona Javobgarlik Printsipiga rioya qilishning ahamiyati. Har bir komponent — Movie, ScreeningManager, Seat va Order — alohida javobgarlikni bajaradi, tizimning qo'llab-quvvatlash mumkin va moslashuvchan bo'lib qolishini ta'minlaydi.

Dizayn tanlovlarimiz — Movie va Screening'ni ajratish, narxlash uchun Strategy naqshini qo'llash — moslashuvchanlik va kengaytirilishni ustuvor biladi. Screening va Ticket'ni birlashtirish kabi muqobil yondashuv modelni soddalashtirishi mumkin, lekin alohida o'rin boshqaruvini murakkablashtiradi.

Bob 6

Unix Fayl Qidirish Tizimini Loyihalash

~10 daq o'qish

Bu bobda biz Unix Fayl Qidirish tizimining dizaynini o'rganamiz. Maqsad — kataloglar, fayllar va filtr mezonlari kabi fayl qidirish tizimidagi asosiy sub'yektlarning abstraktsiyalarini ifodalaydigan sinflarni loyihalashdir. Biz ushbu komponentlar o'rtasidagi muhim o'zaro ta'sirlarni o'zida aks ettiruvchi aniq va funksional strukturani yaratishga harakat qilamiz, bu qidirish tizimini intuitiv va kengaytirilishi mumkin qiladi.

Talablarni Aniqlash

Mana intervyuer tomonidan odatda beriladigan savol namunasi:

> **Intervyuer:** "Tasavvur qiling: siz Unix tizimida muayyan fayllarni — foydalanuvchiga tegishli yoki naqshga mos matn fayllarini — chuqur katalog strukturasida topishga harakat qilayotgan dasturchi bo'lsangiz. Qidiruv buyrug'ini ishga tushurasiz, mezonlaringizni belgilaysiz va tizim mos fayllarni tezda qaytaradi. Sahna ortida u rekursiv ravishda kataloglarni ko'rib chiqadi, fayl atributlarini baholaydi va filtrlaringizni samarali qo'llaydi. Unix Fayl Qidirish tizimini loyihalaylik."

---

> **Nomzod:** find buyrug'i fayllarni qidirish uchun qanday atributlardan foydalanadi?

> **Intervyuer:** Hajm, fayl turi, fayl nomi va egasi kabi mezonlarga asoslanishi mumkin.

> **Nomzod:** Kataloglarni ham boshqarish kerakmi?

> **Intervyuer:** Ha, kataloglar ham alohida fayl turi bilan fayllar sifatida ko'rib chiqiladi.

> **Nomzod:** Buyruq qanday turdagi taqqoslashlarni qo'llab-quvvatlaydi?

> **Intervyuer:** Bu atribut turiga bog'liq. Satrlar uchun 'teng' va 'regex mos kelishi' qo'llab-quvvatlanamiz. Sonlar uchun 'kattaroq', 'teng' va 'kichikroq' qo'llab-quvvatlanamiz.

> **Nomzod:** Bir xil atributda ham bir nechta mezonlarni birlashtirish mumkinmi?

> **Intervyuer:** Ha, bir nechta mezonlar bilan 'va', 'yoki' va 'emas' shartlaridan foydalanib.

> **Nomzod:** Biz katalog va uning ichki kataloglarini rekursiv qidirib, berilgan shartlarga mos keladigan fayllarni qaytaruvchi tizim loyihalashtyapmiz, shundaymi?

> **Intervyuer:** Ha, to'g'ri taxmin.

**Konkret misollar tuzish**

Talablar bilan tanishgach, ularni amalda ko'raylik:

- **Oddiy Qidiruv:** `/` ichida rekursiv ravishda `hajm > 10` bo'lgan fayllarni topish. - **Murakkab Qidiruv:** `/` ichida rekursiv ravishda `((hajm > 10 va hajm < 1000 va egasi = "alice") yoki (hajm > 1000 va !(fayl nomi /prefix.*/ naqshiga mos)))` bo'lgan fayllarni topish.

**Talablar**

Funksional talablar:

- Qidiruv tizimi fayllarni hajm, tur, fayl nomi va egasi kabi atributlar asosida qidira oladi. - Qidiruv tizimi taqqoslash turlarini qo'llab-quvvatlaydi: satrlar uchun 'teng' va 'regex mos kelishi'; sonlar uchun 'kattaroq', 'teng' va 'kichikroq'. - Tizim bir nechta qidiruv mezonlarini mantiqiy operatorlar (va, yoki, emas) yordamida birlashtira oladi. - Fayl qidirish tizimi kataloglar ichida rekursiv qidiruvlarni amalga oshira oladi. - Qidiruv tizimi qidiruv mezonlarini kataloglarga ham, fayllarga ham qo'llashi mumkin.

Funksional bo'lmagan talablar:

- **Kengaytirilish:** Katta katalog daraxtlarini resurs samarali ko'rib chiqish strategiyalari yordamida samarali boshqarish. - **Kengaytirilish:** Asosiy logikani o'zgartirmasdan yangi atributlar va taqqoslash operatorlarini qo'shish imkoniyati. - **Javobgarliklarni ajratish:** Modulli dizayn uchun ko'rib chiqish logikasini filtrlash logikasidan alohida saqlash.

Asosiy Ob'yektlarni Aniqlash

Bizga kerak bo'ladigan asosiy ob'yektlar:

- **FileSearch:** Qidiruv jarayonini boshqaruvchi markaziy sub'yekt. Boshlang'ich File'dan boshlab fayl tizimini rekursiv ko'rib chiqadi va FileSearchCriteria ob'yektiga asoslanib mos fayllarni qaytaradi. - **File:** Hajm, tur, fayl nomi va egasi kabi atributlarni saqlaydigan fayl yoki katalogni modellashtiradi. Ichki kataloglar uchun yozuvlar bilan ierarxik strukturani qo'llab-quvvatlaydi. - **FileSearchCriteria:** Qidiruv shartini inkapsuliyalab, Predicate'ga topshirish orqali File mos kelishini aniqlaydi. Qidiruv bajarilishini shart baholashdan ajratadi. - **Predicate:** File shartga mos kelishini baholash uchun shartnomani belgilaydigan interfeys. Oddiy tekshiruvlarni (`hajm > 10`) ham, murakkab shartlarni (VA, YOKI, EMAS) ham qo'llab-quvvatlaydi. - **SimplePredicate:** Bitta fayl atributini operatorlar yordamida qiymat bilan taqqoslaydigan Predicate'ni amalga oshiradi. - **CompositePredicate:** AndPredicate, OrPredicate va NotPredicate bilan shartlarni birlashtirish uchun Predicate'ni kengaytiradi. - **ComparisonOperator:** Atribut qiymatlarini qanday taqqoslashni belgilaydigan interfeys, amalga oshirishlari bilan: EqualsOperator, RegexMatchOperator, GreaterThanOperator va LessThanOperator.

> **Dizayn tanlovi:** FileSearchCriteria va Predicate'ni bitta sinfga birlashtirish mumkin, lekin bu qidiruv logikasini shart baholash bilan mahkam bog'lab, modulliligi kamaytiradi.

> **Dizayn tanlovi:** File ob'yekti fayllar va kataloglarni bitta sub'yekt sifatida ifodalaydi, bir tekis boshqarish uchun hamma narsani fayl sifatida ko'ruvchi Unix printsipiga amal qiladi.

Sinflar Diagrammasini Loyihalash

### File (Fayl)

Java'ning `java.io.File` sinfiga tayanish o'rniga asosiy sub'yekt sifatida maxsus File sinfini aniqlaymiz. U qidiruv shartlarida ishlatiladigan atributlar uchun `FileAttribute` enum bilan birgalikda ishlatiladi.

> **Dizayn tanlovi:** `FileAttribute` qidiluvchan atributlarning (hajm, egasi va h.k.) qat'iy, type-safe to'plamini ta'minlab, noto'g'ri atribut nomlaridan kelib chiqadigan ish vaqtidagi xatolarni oldini olish uchun enum sifatida belgilangan. O'zgartirish vaqti kabi yangi atribut qo'shish uchun faqat enum'ni kengaytirish kerak.

UML diagram of File class with isDirectory, size, owner, filename, and FileAttribute enum
File class and FileAttribute enum

FileSearch Dizayni

FileSearch sinfi berilgan File'dan boshlab fayl tizimini ko'rib chiqadi, mos fayllarni tanlash uchun FileSearchCriteria ob'yektidan foydalanadi. Ko'rib chiqishni filtrlash logikasidan ajratib, dizayn modulli va kengaytirilishi oson bo'lib qoladi.

UML class diagram of FileSearch showing its search method
FileSearch class

FileSearchCriteria Dizayni

FileSearchCriteria FileSearch va Predicate o'rtasida ko'prik vazifasini bajaradi. U FileSearch'ga nima mos kelishini Predicate'ga topshirish orqali bildiradi.

> **Dizayn tanlovi:** FileSearchCriteria barcha logikani o'zi bajarmasdan fayl qidiruv shartlarini tekshirish uchun Predicate'ga topshiradi. Bu javobgarliklarni aniq saqlaydi — FileSearch ko'rib chiqishni boshqaradi, FileSearchCriteria mezonlarni saqlaydi, Predicate esa shartlarni baholaydi.

UML class diagram of FileSearchCriteria showing its relationship to Predicate
FileSearchCriteria class

Predicate va SimplePredicate Dizayni

Predicate interfeysi yagona `isMatch(File)` metodini belgilaydi. Oddiy shartlar uchun SimplePredicate ComparisonOperator yordamida bitta fayl atributini qiymat bilan taqqoslaydi — masalan, "hajm > 10 mi?" yoki "egasi 'bob' mi?"

UML diagram showing Predicate interface and SimplePredicate with FileAttribute and ComparisonOperator
Predicate interface and SimplePredicate class

ComparisonOperator Dizayni

ComparisonOperator interfeysi fayl atributining qiymatini kutilgan qiymat bilan taqqoslash uchun shartnomani belgilaydi. Type xavfsizligini ta'minlash uchun generics (`<T>`) ishlatamiz. Konkret amalga oshirishlar:

- `EqualsOperator` — ikki qiymat bir xil ekanligini tasdiqlaydi. - `GreaterThanOperator` — bir qiymat kattaroq ekanligini tekshiradi. - `LessThanOperator` — bir qiymat kichikroq ekanligini ta'minlaydi. - `RegexMatchOperator` — satr regex naqshiga mos kelishini baholaydi.

> **Muqobil:** `"equals"` yoki `">"` kabi satrlardan foydalanish validatsiyani ish vaqtiga qoldiradi va istisnolarga olib kelish xavfini tug'diradi. Enum'lar kompilyatsiya vaqtidagi xavfsizlikni ta'minlaydi, lekin yangi operator qo'shish uchun enum'ni o'zgartirish kerak, interfeys asosidagi yondashuv esa mavjud kodni o'zgartirmasdan yangi sinf qo'shish imkonini beradi.

UML diagram showing ComparisonOperator interface with EqualsOperator, GreaterThanOperator, LessThanOperator, and RegexMatchOperator
ComparisonOperator interface and concrete classes

Composite Predicate Dizayni

Haqiqiy qidiruvlar ko'pincha bir nechta shartni birlashtiradi. Oddiylardan murakkab predikatlar qurish uchun **Composite dizayn naqshidan** foydalanamiz.

> **Eslatma:** Composite Pattern haqida ko'proq bilib olish uchun Qo'shimcha O'qish bo'limiga murojaat qiling.

Misol: `((hajm > 10 va hajm < 1000 va egasi = "alice") yoki (hajm > 1000 va !(fayl nomi /prefix.*/ mos)))`

Bu daraxtga aylanadi: - `A = hajm > 10`, `B = hajm < 1000`, `C = egasi = "alice"`, `D = hajm > 1000`, `E = fayl nomi prefix.*` - Natija: `((A va B va C) yoki (D va !(E)))`

Daraxt rekursiv ravishda baholanadi:

Tree diagram showing how AND, OR, and NOT predicates are composed for a complex file search condition
Tree evaluation of composite conditions
UML diagram showing CompositePredicate with AndPredicate, OrPredicate, and NotPredicate implementations
CompositePredicate interface and concrete classes

To'liq Sinflar Diagrammasi

Ierarxik File strukturasidan murakkab predikate logikasigacha barcha sinflarni qurib bo'lganimizdan so'ng, mana UML sinflар diagrammasidagi to'liq tizim.

Full UML class diagram of the Unix File Search system
Complete Class Diagram of File Search

Kod — Unix Fayl Qidirish

### File (Fayl)

```java // Fayl tizimidagi fayl yoki katalogni ifodalaydi public class File { private final boolean isDirectory; private final int size; private final String owner; private final String filename; private final Set<File> entries = new HashSet<>();

public File(final boolean isDirectory, final int size, final String owner, final String filename) { this.isDirectory = isDirectory; this.size = size; this.owner = owner; this.filename = filename; }

public Object extract(final FileAttribute attributeName) { switch (attributeName) { case SIZE -> { return size; } case OWNER -> { return owner; } case IS_DIRECTORY -> { return isDirectory; } case FILENAME -> { return filename; } } throw new IllegalArgumentException("noto'g'ri filtr mezon turi"); }

public void addEntry(final File entry) { entries.add(entry); } // getter metodlari qisqartirish uchun tushirib qoldirildi }

public enum FileAttribute { IS_DIRECTORY, SIZE, OWNER, FILENAME } ```

- `extract()` FileAttribute enum konstantasini uning maydoniga aylantirish orqali muayyan atributning qiymatini oladi; SimplePredicate tomonidan shartlarni baholashda ishlatiladi. - `addEntry()` rekursiv ko'rib chiqish uchun katalog ierarxiyasini quradi.

### Predicate

```java // Barcha fayl qidiruv predikatlar uchun asosiy interfeys public interface Predicate { boolean isMatch(final File inputFile); } ```

### ComparisonOperator (Taqqoslash Operatori)

```java // Barcha taqqoslash operatsiyalari uchun asosiy interfeys public interface ComparisonOperator<T> { boolean isMatch(final T attributeValue, final T expectedValue); }

public class EqualsOperator<T> implements ComparisonOperator<T> { @Override public boolean isMatch(final T attributeValue, final T expectedValue) { return Objects.equals(attributeValue, expectedValue); } }

class GreaterThanOperator<T extends Number> implements ComparisonOperator<T> { @Override public boolean isMatch(final T attributeValue, final T expectedValue) { return Double.compare(attributeValue.doubleValue(), expectedValue.doubleValue()) > 0; } }

class LessThanOperator<T extends Number> implements ComparisonOperator<T> { @Override public boolean isMatch(final T attributeValue, final T expectedValue) { return Double.compare(attributeValue.doubleValue(), expectedValue.doubleValue()) < 0; } }

public class RegexMatchOperator<T extends String> implements ComparisonOperator<T> { @Override public boolean isMatch(final T attributeValue, final T expectedValue) { final Pattern p = Pattern.compile(expectedValue); return p.matcher(attributeValue).matches(); } } ```

> **Amalga oshirish tanlovi:** Generics (`<T>`) kompilyatsiya vaqtida type xavfsizligini ta'minlaydi — raqamli atributlar (Double) faqat sonlar bilan, satr atributlari faqat satrlar bilan taqqoslanadi.

### SimplePredicate

```java // Fayl atributini kutilgan qiymat bilan taqqoslaydigan asosiy predikate public class SimplePredicate<T> implements Predicate { private final FileAttribute attributeName; private final ComparisonOperator<T> operator; T expectedValue;

public SimplePredicate(final FileAttribute attributeName, final ComparisonOperator<T> operator, final T expectedValue) { this.attributeName = attributeName; this.operator = operator; this.expectedValue = expectedValue; }

@Override public boolean isMatch(final File inputFile) { Object actualValue = inputFile.extract(attributeName); if (expectedValue.getClass().isInstance(actualValue)) { return operator.isMatch((T) actualValue, expectedValue); } else { return false; } } } ```

### CompositePredicate

```java public interface CompositePredicate extends Predicate { // Marker interfeys: bir nechta boshqa predikatlarni birlashtiruvchi predikatlarni aniqlaydi }

public class AndPredicate implements CompositePredicate { private final List<Predicate> operands;

public AndPredicate(final List<Predicate> operands) { this.operands = operands; }

@Override public boolean isMatch(final File inputFile) { return operands.stream().allMatch(predicate -> predicate.isMatch(inputFile)); } }

public class OrPredicate implements CompositePredicate { private final List<Predicate> operands;

public OrPredicate(final List<Predicate> operands) { this.operands = operands; }

@Override public boolean isMatch(final File inputFile) { return operands.stream().anyMatch(predicate -> predicate.isMatch(inputFile)); } }

public class NotPredicate implements CompositePredicate { private final Predicate operand;

public NotPredicate(final Predicate operand) { this.operand = operand; }

@Override public boolean isMatch(final File inputFile) { return !operand.isMatch(inputFile); } } ```

- `AndPredicate` va `OrPredicate` istalgan sondagi shartlarni qo'llab-quvvatlash uchun `List<Predicate>` ishlatadi. - `NotPredicate` bitta predikatni o'rab, uning natijasini teskariga aylantiradi.

### FileSearchCriteria

```java // Fayl mos kelishini qidiruv sharti uchun umumlashtiruvchi wrapper sinf public class FileSearchCriteria { private final Predicate predicate;

public FileSearchCriteria(final Predicate predicate) { this.predicate = predicate; }

public boolean isMatch(final File inputFile) { return predicate.isMatch(inputFile); } } ```

> **Amalga oshirish tanlovi:** Predicate'ni FileSearchCriteria'ga o'rash FileSearch'ni fayl tizimini ko'rib chiqishga yo'naltiradi va shart baholashni alohida, qayta ishlatiladigan qatlamga ajratadi.

### FileSearch

```java // Fayl tizimi qidiruvlarini amalga oshirish uchun asosiy sinf public class FileSearch { public List<File> search(final File root, final FileSearchCriteria criteria) { final List<File> result = new ArrayList<>(); final ArrayDeque<File> recursionStack = new ArrayDeque<>(); recursionStack.add(root);

while (!recursionStack.isEmpty()) { File next = recursionStack.pop(); if (criteria.isMatch(next)) { result.add(next); } for (File entry : next.getEntries()) { recursionStack.push(entry); } } return result; } } ```

> **Amalga oshirish tanlovi:** Stack asosidagi ko'rib chiqish (`ArrayDeque`) chuqur fayl tizimlarida stack overflow'ning oldini oladi. Rekursiv chaqiruvlar kichikroq strukturalar uchun ishlaydi, lekin chuqur joylashtirilgan kataloglarda muvaffaqiyatsiz bo'lishi xavfi bor.

Chuqur O'rganish Mavzusi

### Fayl Qidirish Testi

Mana "'ge.*' naqshiga mos egaga tegishli katalog bo'lmagan fayllar" sharti uchun test holati:

```java public class FileSearchTest { @Test public void testFileSearch() { final File root = new File(true, 0, "adam", "root"); final File a = new File(false, 2000, "adam", "a"); final File b = new File(false, 3000, "george", "b");

root.addEntry(a); root.addEntry(b);

// Qidiruv mezonlari: "ge.*" naqshiga mos egaga tegishli katalog bo'lmagan fayllar final FileSearchCriteria criteria = new FileSearchCriteria( new AndPredicate(List.of( new SimplePredicate<>( FileAttribute.IS_DIRECTORY, new EqualsOperator<>(), false), new SimplePredicate<>( FileAttribute.OWNER, new RegexMatchOperator<>(), "ge.*"))));

final FileSearch fileSearch = new FileSearch(); final List<File> result = fileSearch.search(root, criteria);

assertEquals(1, result.size()); assertEquals("b", result.get(0).getFilename()); } } ```

Bu test 'adam' va 'george'ga tegishli ikki fayldan iborat root katalogini o'rnatadi va faqat 'b' fayli ('george'ga tegishli) IS_DIRECTORY=false va OWNER 'ge.*' naqshiga mos keladigan `AndPredicate`ga mos kelishini tekshiradi.

Xulosa

UNIX fayl qidirish tizimi to'liq amalga oshirilgan va sinovdan o'tkazilgandan so'ng asosiy o'rganishlar:

- File, FileSearch, FileSearchCriteria va Predicate o'rtasida javobgarliklarni aniq taqsimlash. - FileSearch'ni FileSearchCriteria'dan ajratish va ComparisonOperator'da generics ishlatish kengaytirilishni va type xavfsizligini yaxshilaydi. - FileSearchCriteria'ni Predicate bilan birlashtirish mumkin, lekin bu ularning alohida rollarini xiralashtirib, ko'rib chiqishga ta'sir qilmasdan shart logikasini almashtirish qiyinlashadi.

Qo'shimcha O'qish: Composite Dizayn Naqshi

Composite naqshi ob'yektlarni daraxt strukturalariga tashkil etib, ularni alohida ob'yektlar kabi ko'rib chiqish imkonini beradi.

**Muammo:** Sizda Fayllar va Papkalar bor. Papka Fayllar va kichikroq Papkalarni o'z ichiga olishi mumkin. `hajm > 10` kabi shartga mos barcha elementlarni bu butun struktura bo'yicha qanday topasiz?

**Yechim:** Fayllar va Papkalar bilan shart tekshirish metodini e'lon qiluvchi umumiy interfeys orqali ishlash: - Fayl uchun: bevosita shartga mos kelishini tekshiradi. - Papka uchun: har bir o'z ichiga olgan elementni tekshiradi, ichki papkalarga jarayonni rekursiv qo'llaydi.

**Qachon ishlatish kerak:** - Daraxtsimon ob'yekt strukturasini qurish kerak bo'lganda. - Mijoz kodi ham oddiy, ham murakkab elementlarni bir tekis ko'rib chiqishini istasangiz.

UML class diagram illustrating the Composite design pattern with Item interface, File and Folder implementations
Composite pattern: Item interface with File and Folder
Bob 7

Avtomat Savdo Mashinasini Loyihalash

~9 daq o'qish

Bu bobda biz foydalanuvchilarga mahsulotlarni tanlash va xarid qilish, tovarlarni berish, inventarni boshqarish va to'lovlarni qayta ishlash imkonini beruvchi avtomat savdo mashinasi tiziminin dizaynini o'rganamiz. Haqiqiy avtomat savdo mashinalari tangalar beriш mexanizmi, karta o'quvchilari va sensorli ekranlar kabi apparat komponentlarini o'z ichiga olsa ham, biz tizimning holatlari, ma'lumotlari va asosiy funksiyalarini modellashtirshga e'tibor qaratamiz.

Illustration of a vending machine
Vending Machine

Talablarni Aniqlash

Mana intervyuer tomonidan odatda beriladigan savol namunasi:

> **Intervyuer:** "Tasavvur qiling: siz avtomat savdo mashinasi oldida turib, gazak yemoqchi bo'lasiz. Bir oz pul tashlaysiz, sevimli mahsulotingizni tanlab, bir necha soniyada u tegishli joyga tushadi. Kerak bo'lsa mashina to'g'ri qayta pulni ham beradi. Sahna ortida tizim inventarni kuzatib, to'lovlarni boshqarib, hamma narsaning silliq ishlashini ta'minlaydi. Endi bularning hammasini qiladigan avtomat savdo mashinasini loyihalaylik."

---

> **Nomzod:** Avtomat savdo mashinasi turli turdagi mahsulotlarni qo'llab-quvvatlaydimi?

> **Intervyuer:** Ha, avtomat savdo mashinasi gazaklar, ichimliklar va boshqa mahsulotlar kabi turli tovarlarni qo'llab-quvvatlaydi.

> **Nomzod:** Mahsulotlar avtomat savdo mashinasida qanday tartibda joylashtirilgan?

> **Intervyuer:** Mahsulotlar muayyan raflariga qo'yilgan, har bir rafda faqat bitta turdagi mahsulot bir vaqtda bo'ladi. Har bir mahsulotning noyob mahsulot kodi va narx belgisi bor.

> **Nomzod:** Avtomat savdo mashinasida to'lov qanday amalga oshiriladi?

> **Intervyuer:** Avtomat savdo mashinasi faqat naqd to'lovlarni qabul qilishi va kerak bo'lsa qayta pul berishi kerak.

> **Nomzod:** Foydalanuvchi zapas tugagan mahsulotni tanlaganda avtomat savdo mashinasi qanday munosabatda bo'ladi?

> **Intervyuer:** Tizim mahsulot mavjudligini tekshirishi kerak. Agar yo'q bo'lsa, xato xabarini ko'rsatishi kerak.

> **Nomzod:** Foydalanuvchi mahsulotning to'liq narxidan kam pul tashlasa, asta-sekin qo'sha oladimi?

> **Intervyuer:** Bu dizayn uchun foydalanuvchilar to'liq miqdorni bir qadamda tashlasin deb faraz qilaylik. Yetarli bo'lmasa, avtomat savdo mashinasi pulni qaytarib, xato xabarini ko'rsatishi kerak.

> **Nomzod:** Avtomat savdo mashinasiga kirishda cheklovlar bormi?

> **Intervyuer:** Foydalanuvchilar va administratorlar turli imtiyozlar bilan kirishlari mumkin. Foydalanuvchilar mahsulotlarni tanlashi va xarid qilishi mumkin. Administratorlar mahsulotlarni qo'shib yoki olib tashlashlari mumkin.

> **Nomzod:** Xavfsizlik yoki inventarni kuzatish talablari bormi?

> **Intervyuer:** Ha. Avtomat savdo mashinasi inventarni kuzatishi kerak va faqat administrator mahsulotlarni qo'shib yoki olib tashlashi mumkin.

**Talablar**

Funksional talablar:

- **Mahsulot tanlash:** Foydalanuvchilar noyob mahsulot kodi, tavsifi va narx belgisi bo'lgan mahsulotlardan tanlashlari mumkin. - **Inventar boshqaruvi:** Mahsulotlar raflarda saqlanadi. Tizim har bir mahsulot rafidagi inventar darajasini kuzatadi. - **To'lovni qayta ishlash:** Tizim faqat naqd to'lovlarni qabul qiladi va kerak bo'lganda qayta pul hisoblashi mumkin.

Funksional bo'lmagan talablar:

- Foydalanuvchilarni yo'naltiruvchi aniq xato xabarlari bilan intuitiv UI. - Xavfsizlik: faqat administratorlar mahsulotlarni qo'shishi, olib tashlashi yoki yangilashi mumkin. Naqd tranzaksiyalar buzish urinishlaridan himoya qilinishi kerak.

Foydalanish Holatlari Diagrammasi

Foydalanish holatlari diagrammasi aktyorlarning avtomat savdo mashinasi tizimi bilan qanday muloqot qilishini ko'rsatadi.

**Foydalanuvchi aktyor:** - Pul Tashlash, Mahsulot Tanlash, Mahsulot Olish, Qayta Pul Olish

**Administrator aktyor:** - Mahsulot Qo'shish, Mahsulot Olib Tashlash, Inventarni Yangilash

**Tizim aktyor:** - To'lovni Qayta Ishlash, Mahsulot Berish, Inventarni Tekshirish, Xabar Ko'rsatish

Use case diagram showing User, Admin, and System actors with their respective use cases
Use Case Diagram of a Vending Machine

Asosiy Ob'yektlarni Aniqlash

- **VendingMachine (Avtomat savdo mashinasi):** Operatsiyalarni muvofiqlashtiruvchi va asosiy kirish nuqtasi bo'lgan markaziy sub'yekt. "God object" bo'lib ketmasligi uchun Facade naqshidan foydalanadi. - **Product (Mahsulot):** Avtomat savdo mashinasida saqlanadigan elementlarni ifodalaydi — identifikator, narx va tavsif. Mahsulotlar ular saqlanadigan raflarga bog'langan. - **Rack (Raf):** Bir nechta birlik bilan bitta mahsulot turini saqlaydigan belgilangan slot. Dispenser apparatini o'z ichiga oladi. - **InventoryManager:** Avtomat savdo mashinasidagi inventar darajasini kuzatadi. - **PaymentProcessor:** To'lovni qayta ishlash uchun tangalar beriш mexanizmi bilan muloqot qiladi, balansni kuzatadi va qayta pulni hisoblaydi.

> **Dizayn tanlovi:** Mahsulotlar raflarga bog'langan, chunki raflar fizik saqlash joylarini ifodalaydi. Bu Yagona Javobgarlik Printsipiga mos keladi — mahsulotlar o'z saqlashini boshqarmaydi.

Sinflar Diagrammasini Loyihalash

### Product (Mahsulot)

Product sinfi atributlari o'z ichiga oladi: mahsulot kodi, tavsif va narx.

> **Dizayn tanlovi:** Inventar miqdori Product'da modellanmagan — u faqat o'ziga xos xususiyatlarni inkapsuliyalaydi. Doimiy o'zgaruvchi zaxira darajasi alohida InventoryManager tomonidan boshqariladi, bu tozaroq ob'yekt parchalanish va Yagona Javobgarlik Printsipini qo'llab-quvvatlaydi.

UML class diagram for Product with productCode, description, and unitPrice
Product class

Rack Dizayni

Rack sinfi bitta mahsulot bilan bog'liq va bir nechta birlikni saqlaydigan bitta raf joyini modellashtiradi.

> **Dizayn tanlovi:** Rack `dispenseProductFromRack` kabi metodlarni o'z ichiga olmaydi. Buning o'rniga inventar miqdorini va mahsulot ma'lumotlarini boshqarishga e'tibor qaratadi. Berish InventoryManager'ga topshirilgan, Yagona Javobgarlik Printsipiga amal qiladi.

UML class diagram for Rack with rackCode, product, and count
Rack class

InventoryManager Dizayni

InventoryManager mahsulotlarni kuzatish va saqlashni boshqaradi. Mahsulotlarni qo'shish, olib tashlash va berish operatsiyalarini qo'llab-quvvatlaydi.

Asosiy metodlar: - `dispenseProductFromRack()` — mahsulot beradi va inventar darajasini kamaytiradi. - `updateRack()` — administratorga ommaviy yangilanishlar uchun butun raf strukturasini almashtirish imkonini beradi. - `addRack()` / `removeRack()` — alohida raf o'zgartirishlari uchun granular metodlar.

> **Dizayn tanlovi:** `updateRack(Map racks)` ommaviy ma'muriy yangilanishlar uchun taqdim etilgan. Ko'p holatlarda nojo'ya o'zgarishlarni cheklash uchun granular `addRack`/`removeRack`ni afzal ko'ring. Thread xavfsizligi uchun o'zgarmas to'plamlarni yoki himoyaviy nusxalashni ko'rib chiqing.

UML class diagram for InventoryManager showing its rack management methods
InventoryManager class

PaymentProcessor va Transaction Dizayni

**PaymentProcessor** to'lovni qabul qilishni boshqaradi, joriy balansni kuzatadi va qayta pulni qaytaradi. Tangalar qabul qilish mexanizmi bilan muloqot qiladi.

**Transaction** xaridning joriy holatini kuzatuvchi ma'lumotlar strukturasi sifatida ishlaydi. Afzalliklari: - Tanlangan mahsulot, uning rafi va umumiy narxni inkapsuliyalaydi. - Davom etayotgan tranzaksiyalarning tartibli yozuvini saqlaydi. - Muvofiqlikni yaxshilaydi — PaymentProcessor miqdorni ayiradi, InventoryManager mahsulot beradi va Transaction ularni birlashtiradi.

UML class diagram for PaymentProcessor with currentBalance and payment methods
PaymentProcessor class
UML class diagram for Transaction with product, rack, and totalAmount
Transaction class

VendingMachine Dizayni

VendingMachine asosiy komponent bo'lib, mijozlarga (mashinaning dasturiy/apparat interfeyslari) yagona interfeys taqdim etuvchi **Fasad** sifatida ishlaydi.

> **Dizayn tanlovi:** VendingMachine'ning "god object" bo'lib ketishining oldini olish uchun fasadlar yengil bo'lib qoladi va boshqa sinflarga — mahsulot boshqaruvi uchun InventoryManager'ga, to'lovni boshqarish uchun PaymentProcessor'ga — topshiradi.

> **Eslatma:** Facade naqshi haqida ko'proq bilib olish uchun Avtoturargoh bobiga murojaat qiling.

UML class diagram for VendingMachine showing its delegation to InventoryManager and PaymentProcessor
VendingMachine class (facade)

To'liq Sinflar Diagrammasi

Quyida avtomat savdo mashinasi tizimining to'liq sinflар diagrammasi keltirilgan.

Full UML class diagram of the Vending Machine system
Complete Class Diagram of Vending Machine

Kod — Avtomat Savdo Mashinasi

### Product (Mahsulot)

```java class Product { final String productCode; final String description; final BigDecimal unitPrice;

public Product(String productCode, String description, BigDecimal unitPrice) { this.productCode = productCode; this.description = description; this.unitPrice = unitPrice; } } ```

> **Amalga oshirish tanlovi:** Aniqlik va yaxlitlash nazorati uchun `unitPrice` kabi pul qiymatlari uchun `BigDecimal` ishlatish. Valyuta uchun `float` yoki `double` dan saqlaning — ular aniqlik xatolarini kiritadi. `productCode` kabi identifikatorlar uchun, qiymatlar raqamli bo'lsa ham, `String` ishlatish.

### InventoryManager va Rack

Raf kodi bo'yicha samarali O(1) qidirish uchun `HashMap<String, Rack>` ishlatamiz.

```java public class InventoryManager { private Map<String, Rack> racks;

public InventoryManager() { racks = new HashMap<>(); }

public Product getProductInRack(String rackCode) { return racks.get(rackCode).getProduct(); }

public void dispenseProductFromRack(Rack rack) { if (rack.getProductCount() > 0) { rack.setCount(rack.getProductCount() - 1); } else { throw new IllegalStateException("Mahsulot berib bo'lmaydi. Raf bo'sh."); } }

public void updateRack(Map<String, Rack> racks) { this.racks = racks; }

public Rack getRack(String name) { return racks.get(name); } } ```

```java public class Rack { private final String rackCode; private final Product product; private int count;

public Rack(final String rackCode, final Product product, final int count) { this.rackCode = rackCode; this.product = product; this.count = count; }

public Product getProduct() { return product; }

public int getProductCount() { return count; } } ```

### PaymentProcessor

```java public class PaymentProcessor { private BigDecimal currentBalance = BigDecimal.ZERO;

public void addBalance(BigDecimal amount) { currentBalance = currentBalance.add(amount); }

public void charge(BigDecimal amount) { currentBalance = currentBalance.subtract(amount); }

public BigDecimal returnChange() { BigDecimal change = currentBalance; currentBalance = BigDecimal.ZERO; return change; }

public BigDecimal getCurrentBalance() { return currentBalance; } } ```

### VendingMachine (Avtomat savdo mashinasi)

```java class VendingMachine { private final List<Transaction> transactionHistory; private final InventoryManager inventoryManager; private final PaymentProcessor paymentProcessor; private Transaction currentTransaction; private VendingMachineState currentState;

public VendingMachine() { transactionHistory = new ArrayList<>(); currentTransaction = new Transaction(); inventoryManager = new InventoryManager(); paymentProcessor = new PaymentProcessor(); this.currentState = new NoMoneyInsertedState(); }

void setRack(Map<String, Rack> rack) { inventoryManager.updateRack(rack); }

void insertMoney(final BigDecimal amount) { paymentProcessor.addBalance(amount); }

void chooseProduct(String rackId) { final Product product = inventoryManager.getProductInRack(rackId); currentTransaction.setRack(inventoryManager.getRack(rackId)); currentTransaction.setProduct(product); }

Transaction confirmTransaction() throws InvalidTransactionException { validateTransaction(); paymentProcessor.charge(currentTransaction.getProduct().getUnitPrice()); inventoryManager.dispenseProductFromRack(currentTransaction.getRack()); currentTransaction.setTotalAmount(paymentProcessor.returnChange()); transactionHistory.add(currentTransaction); Transaction completedTransaction = currentTransaction; currentTransaction = new Transaction(); return completedTransaction; }

private void validateTransaction() throws InvalidTransactionException { if (currentTransaction.getProduct() == null) { throw new InvalidTransactionException("Noto'g'ri mahsulot tanlovi"); } else if (currentTransaction.getRack().getProductCount() == 0) { throw new InvalidTransactionException("Mahsulot uchun inventar yetarli emas."); } else if (paymentProcessor.getCurrentBalance() .compareTo(currentTransaction.getProduct().getUnitPrice()) < 0) { throw new InvalidTransactionException("Mablag' yetarli emas"); } }

public List<Transaction> getTransactionHistory() { return Collections.unmodifiableList(transactionHistory); }

public void cancelTransaction() { paymentProcessor.returnChange(); currentTransaction = new Transaction(); }

public InventoryManager getInventoryManager() { return inventoryManager; } } ```

- `insertMoney()` — PaymentProcessor orqali mashina balansiga miqdor qo'shadi. - `chooseProduct()` — InventoryManager'dan mahsulot va rafni oladi, joriy tranzaksiyaga bog'laydi. - `confirmTransaction()` — tranzaksiyani tekshiradi, to'lovni qayta ishlaydi, mahsulot beradi, tarixni yangilaydi.

Chuqur O'rganish Mavzulari

### State Pattern bilan Vazifalar Ketma-ketligini Ta'minlash

Foydalanuvchilar mahsulotni tanlashdan oldin pul tashlashini ta'minlash uchun **State Pattern**ni kiritamiz.

> **Eslatma:** State Pattern haqida ko'proq bilib olish uchun Qo'shimcha O'qish bo'limiga murojaat qiling.

Uch alohida holat:

**NoMoneyInsertedState (Pul Tashlanmagan Holat):** - Boshlang'ich holat. "Davom etish uchun pul tashlang." ko'rsatadi. - Faqat pul tashlashga ruxsat beradi. Mahsulot tanlash istisnoni chiqaradi. - Pul tashlaganda MoneyInsertedState'ga o'tadi.

**MoneyInsertedState (Pul Tashiangan Holat):** - "Mahsulot tanlang." ko'rsatadi. - Mahsulot tanlashga ruxsat beradi; qo'shimcha pul tashlashning oldini oladi. - Mahsulot mavjudligi va mablag' yetarlililigini tekshiradi. - Muvaffaqiyatli mahsulot tanlaganda DispenseState'ga o'tadi.

**DispenseState (Berish Holati):** - "Mahsulot berilmoqda..." yoki "Qayta pulingizni oling." ko'rsatadi. - Berish ishini boshqaradi va yakunlangandan so'ng mashinani boshlang'ich holatga qaytaradi. - Jarayon tugamaguncha keyingi harakatlarning oldini oladi.

Bu ketma-ketlikni kafolatlaydi: **Pul Tashlash → Mahsulot Tanlash → Mahsulot Berish**.

UML diagram showing VendingMachineState interface with NoMoneyInsertedState, MoneyInsertedState, and DispenseState
VendingMachineState interface diagram

State Pattern Kodi

### VendingMachineState Interfeysi

```java public interface VendingMachineState { void insertMoney(VendingMachine VM, double amount);

void selectProductByCode(VendingMachine VM, String productCode) throws InvalidStateException;

void dispenseProduct(VendingMachine VM) throws InvalidStateException;

String getStateDescription(); } ```

### NoMoneyInsertedState

```java public class NoMoneyInsertedState implements VendingMachineState { @Override public void insertMoney(VendingMachine VM, double amount) { VM.addBalance(amount); VM.setState(new MoneyInsertedState()); }

@Override public void selectProductByCode(VendingMachine VM, String productCode) throws InvalidStateException { throw new InvalidStateException("Pul tashlamasdan mahsulot tanlab bo'lmaydi."); }

@Override public void dispenseProduct(VendingMachine VM) throws InvalidStateException { throw new InvalidStateException("Pul tashlamasdan mahsulot berib bo'lmaydi."); }

@Override public String getStateDescription() { return "Pul Tashlanmagan Holat - Davom etish uchun pul tashlang"; } } ```

MoneyInsertedState va DispenseState bir xil strukturaga amal qiladi.

Xulosa

Bu bobda biz Avtomat Savdo Mashinasi tizimini loyihalab, amalga oshirdik. Asosiy o'rganishlar:

- Product, Rack, InventoryManager va PaymentProcessor bo'yicha javobgarliklarni taqsimlash, ularni fasad ostida birlashtirish. - Facade naqshi tashqi interfeysni soddalashtirdi, Yagona Javobgarlik Printsipiga amal qildi. - State Pattern (chuqur o'rganish) qat'iy harakatlar ketma-ketligini ta'minlab, to'lovsiz berish kabi noto'g'ri xatti-harakatlarning oldini oladi.

Intervyularda asosiy funksiyadan keyin validatsiya va xato boshqaruviga e'tibor qarating, ayniqsa noto'g'ri xatti-harakat moliyaviy yo'qotishga olib kelishi mumkin bo'lgan tizimlar uchun.

Qo'shimcha O'qish: State Dizayn Naqshi

State naqshi ob'yektga uning ichki holati o'zgarganda xatti-harakatini o'zgartirishga imkon beradi, go'yo boshqa sinf sifatida harakat qilayotgandek.

**Muammo:** Qizil, Sariq va Yashil holatlari bo'lgan Svetofor. Bu holatlarni boshqarish uchun shartli ifodalardan foydalanish ko'proq holatlar qo'shilganda kengaytirilish va qo'llab-quvvatlash muammolariga olib keladi.

**Yechim:** Har bir holat xatti-harakatini alohida sinfga (RedLightState, GreenLightState, YellowLightState) inkapsuliyalash. Kontekst (TrafficLight) joriy holat ob'yektiga havola saqlaydi va holatga bog'liq vazifalarni unga topshiradi. Holat o'tishlari shunchaki joriy holat ob'yektini almashtiradi.

**Qachon ishlatish kerak:** - Ob'yektning xatti-harakati uning ichki holatiga qarab o'zgarganda. - Holat boshqaruvi uchun katta shartli ifodalardan qochmoqchi bo'lganda. - Holatlar sinflarga aniq ajratilishi mumkin bo'lgan alohida xatti-harakatlarga ega bo'lganda.

UML class diagram illustrating the State design pattern with TrafficLight context and state implementations
State design pattern (traffic light example)
Bob 8

Lift Tizimini Loyihalash

~9 daq o'qish

Bu bobda biz Lift Tizimining ob'yektga yo'naltirilgan dizaynini o'rganamiz. Boshqa mashhur intervyu muammolari bilan taqqoslaganda, bu muammo ma'lumotlarni modellashtirish o'rniga xatti-harakatlarni modellashtirshga ko'proq urg'u beradi. Yondashuvimiz real liftlarni qanday ifodalash, lift holatini, kiruvchi koridor chaqiruv so'rovlarini va lift harakatini belgilovchi algoritmni loyihalash kabi asosiy komponentlarni loyihalashga e'tibor qaratadi.

Illustration of elevator system in an office building
Elevator System

Talablarni Aniqlash

Mana intervyuer tomonidan odatda beriladigan savol namunasi:

> **Intervyuer:** "Tasavvur qiling: siz bir qancha bir xil lift kabinalari bo'lgan ofis binosida bo'lasiz va ularning barchasi bir xil qavatlar to'plamiga xizmat qiladi. O'z qavatingizdagi 'yuqori' yoki 'quyi' tugmasini bosasiz va lift tezda yetib keladi. Ichida panel tugmachalaridan o'z qavatingiizni tanlab, lift sizni o'sha yerga olib boradi. Sahna ortida tizim lift tayinlashlarni samarali boshqaradi va noto'g'ri yo'nalishdagi so'rovlarni e'tiborsiz qoldiradi. Endi bularning hammasini boshqaradigan lift tizimini loyihalaylik."

---

> **Nomzod:** Biz faqat ofis binosilar uchun loyihalayapmizmi, yoki boshqa turdagi liftlarni ham ko'rib chiqish kerakmi?

> **Intervyuer:** Faqat ofis binolari uchun.

> **Nomzod:** Barcha lift kabinalari bir xil qavatlar to'plamiga xizmat qiladimi?

> **Intervyuer:** Ha, barcha lift kabinalari har bir qavatga xizmat qila oladi.

> **Nomzod:** Tizim qaysi liftni yuborish kerakligini aniqlash uchun qanday strategiyadan foydalanishi kerak?

> **Intervyuer:** Muayyan strategiya sizning ixtiyoringizdagi. Ideal holda u moslashtirilishi mumkin bo'lishi kerak — strategiyalarni oson almashtirish imkoniyati bo'lsin. U birinchi kelgan birinchi xizmat ko'rsatiladi yoki boshqa strategiyalar bo'lishi mumkin.

> **Maslahat:** Eng yuqori qavat faqat 'quyi' tugmasiga ega bo'lishi kerak, eng quyi qavat esa faqat 'yuqori' tugmasiga ega bo'lishi kerak. Bu tafsilotni dizayn jarayonida tan olish yaxshi, lekin asosiy e'tibor markazida bo'lmasa, uni muhim deb hisoblash shart emas.

**Talablar**

Funksional talablar:

- Tizim bir xil qavatlar to'plamiga xizmat qiluvchi bir nechta lift kabinasini boshqaradi. - Har bir qavatda lift chaqirish uchun 'yuqori' va 'quyi' koridor tugmalari mavjud. - Har bir lift kabinasi o'zining joriy qavatini va holatini (yuqoriga harakatlanmoqda, pastga, yoki bekor) ko'rsatadi. - Har bir lift kabinasida har bir qavat uchun tugmachalar bo'lgan ichki boshqaruv paneli mavjud. - Foydalanuvchi liftning joriy harakatiga qarama-qarshi yo'nalishdagi qavat tugmasini bossa, so'rov e'tiborsiz qoldiriladi.

Funksional bo'lmagan talablar:

- Dispatching algoritmi optimallashtirish strategiyalari o'rtasida oson almashinishga imkon beruvchi moslashtirish imkoniyatiga ega bo'lishi kerak.

**Lift Boshqaruv Panellari:** - **Koridor Tugmalari (Tashqarida):** Har bir qavatda joylashgan — 'yuqori' yuqoriga ketuvchi liftni chaqirish uchun, 'quyi' pastga ketish uchun. - **Qavat Tugmalari (Ichkarida):** Kabina ichidagi boshqaruv panelida, har bir tugma muayyan qavatga mos keladi.

Foydalanish Holatlari Diagrammasi

**Yo'lovchi aktyor:** - Liftni Chaqirish (koridor tugmasini bosish) - Qavatni Tanlash (kabina ichida qavat tugmasini bosish)

**Tizim aktyor:** - Liftni Tayinlash, Liftni Harakatlantirish, Lift Holatini Hisobot Berish

Use case diagram showing Passenger and System actors with elevator use cases
Use Case Diagram of Elevator Control System

Asosiy Ob'yektlarni Aniqlash

- **ElevatorSystem:** Asosiy interfeys taqdim etuvchi fasad sinfi. Umumiy operatsiyani muvofiqlashtiradi, barcha lift kabinasi holatlarini kuzatadi va koridor chaqiruv so'rovlarini ElevatorDispatch'ga topshiradi. - **ElevatorDispatch:** Dispatching strategiyasi yordamida eng mos liftni tayinlab, koridor chaqiruvlarini boshqaradi. - **ElevatorCar:** Yo'lovchilarni tashuvchi bitta lift birligi. Ichki boshqaruv paneli va maqsad qavatlar navbati bilan mustaqil ishlaydi.

Sinflar Diagrammasini Loyihalash

Foydalanish holatlari asosiy ma'lumotlar modeliga qaraganda aniqroq bo'lganligi sababli, biz xatti-harakatlar va foydalanuvchi muloqotlaridan boshlaб, ularni asosiy sinflarga aylantiramiz.

### ElevatorSystem

ElevatorSystem sinfi barcha lift kabinalarini boshqarish uchun API taqdim etuvchi markaziy kontroller. Uchta asosiy javobgarlik: - **Holat olish:** Har bir liftning joriy holatini tekshirish. - **Lift chaqirish:** Foydalanuvchi koridor tugmasini bosganida, liftni tayinlash so'rovini ishga tushiradi. - **Manzilni tanlash:** Lift ichida foydalanuvchi qavat tugmasini bosadi.

> **Maslahat:** OOD'da narsalarni to'g'ri nomlash juda muhim. Bitta lift kabinasi va butun tizim o'rtasida chalkashlikni oldini olish uchun System, Dispatch yoki Strategy kabi aniq qo'shimchalardan foydalaning.

UML class diagram for ElevatorSystem with elevators list and dispatchController
ElevatorSystem class

ElevatorCar, ElevatorStatus va Direction

**ElevatorCar** lift kabinasining xatti-harakatlarini modellashtiradi. Maqsad qavatlar navbatini saqlaydi va holat boshqaruvini ElevatorStatus'ga topshiradi.

**ElevatorStatus** liftning joriy qavati va yo'nalishining momentli tasvirini taqdim etadi. Lift harakatlanayotganda dinamik ravishda yangilanadi.

**Direction** enum type-safe harakat yo'nalishini taqdim etadi: UP, DOWN, IDLE. Enum'dan foydalanish keraksiz yo'nalish o'zgarishlarining oldini oladi va so'ralgan qavatga allaqachon qarab harakat qilayotgan liftlarga ustunlik berishga yordam beradi.

> **Dizayn tanlovi:** Lift holatini ElevatorStatus'ga ajratish qayta foydalanish va aniqlikni oshiradi, holat bog'liq logikani mustaqil boshqarish va ElevatorCar'ni o'zgartirmasdan kelajakdagi atributlarni (masalan, eshik holati) qo'shish imkonini beradi.

UML class diagram for ElevatorCar with status, targetFloors queue, and key methods
ElevatorCar class
UML diagram showing ElevatorStatus with currentFloor and currentDirection, and Direction enum
ElevatorStatus class and Direction enum

ElevatorDispatch va DispatchingStrategy

ElevatorDispatch koridor tugma so'rovlarini boshqaradi va mos liftni tayinlaydi. Dispatching logikasi algoritmlar o'rtasida dinamik tanlash uchun **Strategy Pattern**'iga tayanadi.

> **Eslatma:** Strategy Pattern haqida ko'proq bilib olish uchun Avtoturargoh bobiga murojaat qiling.

Umumiy dispatching jarayoni: 1. So'rov va lift holatlarini **Ko'rib chiqish**. 2. Strategiyaga asoslanib (yaqinlik, yo'nalish, kutish vaqtini minimallash) eng yaxshi lift kabinasini **Tanlash**. 3. Tanlangan liftning keyingi bekatlarini **Yangilash**.

Odatiy dispatching strategiyalari: - **FCFS (Birinchi Kelgan, Birinchi Xizmat Ko'rgan):** Keyingi mavjud liftga tayinlaydi, oddiy lekin eng samarali bo'lmasligi mumkin. - **SSTF (Eng Qisqa Qidirish Vaqti Birinchi):** To'xtab turgan yoki to'g'ri yo'nalishda harakat qilayotgan, so'ralgan qavatga eng yaqin liftni tayinlaydi. - **Dinamik Strategiyalar:** Tirbandlik naqshlariga qarab moslashtiriladi — band vaqtlarda 'yuqori o'tkazuvchanlik', tinch soatlarda FCFS.

UML diagram showing ElevatorDispatch delegating to DispatchingStrategy with FCFS and SSTF implementations
ElevatorDispatch class and DispatchingStrategy interface

To'liq Sinflar Diagrammasi

Quyida lift tizimining to'liq sinflар diagrammasi keltirilgan.

Full UML class diagram of the Elevator System showing all classes and relationships
Complete Class Diagram of Elevator System

Kod — Lift Tizimi

### ElevatorSystem

```java public class ElevatorSystem { private final List<ElevatorCar> elevators; private final ElevatorDispatch dispatchController;

public ElevatorSystem(List<ElevatorCar> elevators, DispatchingStrategy strategy) { this.elevators = elevators; this.dispatchController = new ElevatorDispatch(strategy); }

public List<ElevatorStatus> getAllElevatorStatuses() { List<ElevatorStatus> statuses = new ArrayList<>(); for (ElevatorCar elevator : elevators) { statuses.add(elevator.getStatus()); } return statuses; }

public void requestElevator(int currentFloor, Direction direction) { dispatchController.dispatchElevatorCar(currentFloor, direction, elevators); }

public void selectFloor(ElevatorCar car, int destinationFloor) { car.addFloorRequest(destinationFloor); } } ```

- `requestElevator()` — foydalanuvchi koridor tugmasini bosadi, ElevatorDispatch'ga topshiradi. - `selectFloor()` — lift ichidagi foydalanuvchi qavat tugmasini bosadi, ElevatorCar tomonidan to'g'ridan-to'g'ri boshqariladi.

### ElevatorCar

```java public class ElevatorCar { private ElevatorStatus status; private final Queue<Integer> targetFloors;

public ElevatorCar(int startingFloor) { this.status = new ElevatorStatus(startingFloor, Direction.IDLE); this.targetFloors = new LinkedList<>(); }

public ElevatorStatus getStatus() { return status; }

public void addFloorRequest(int floor) { if (!targetFloors.contains(floor)) { targetFloors.offer(floor); updateDirection(floor); } }

public boolean isIdle() { return targetFloors.isEmpty(); }

private void updateDirection(int targetFloor) { if (status.getCurrentFloor() < targetFloor) { status = new ElevatorStatus(status.getCurrentFloor(), Direction.UP); } else if (status.getCurrentFloor() > targetFloor) { status = new ElevatorStatus(status.getCurrentFloor(), Direction.DOWN); } } // getter'lar qisqartirish uchun tushirib qoldirildi } ```

> **Amalga oshirish tanlovi:** `targetFloors` uchun `Queue` (FIFO) adolatni ta'minlaydi — qavat so'rovlari qabul qilingan tartibda bajariladi. `PriorityQueue` qavatlarni yaqinligi bo'yicha saralash orqali sayohat vaqtini tejashi mumkin, lekin qayta tartibga solish yo'lovchilarni chalkashtirib qo'yishi mumkin va noto'g'ri yo'nalishdagi bekatlarning oldini olish uchun qo'shimcha logika talab etadi.

### ElevatorDispatch

```java public class ElevatorDispatch { private final DispatchingStrategy strategy;

public ElevatorDispatch(DispatchingStrategy strategy) { this.strategy = strategy; }

public void dispatchElevatorCar(int floor, Direction direction, List<ElevatorCar> elevators) { ElevatorCar selectedElevator = strategy.selectElevator(elevators, floor, direction); if (selectedElevator != null) { selectedElevator.addFloorRequest(floor); } } } ```

### Birinchi Kelgan, Birinchi Xizmat Ko'rgan Strategiyasi

```java public class FirstComeFirstServeStrategy implements DispatchingStrategy { @Override public ElevatorCar selectElevator(List<ElevatorCar> elevators, int floor, Direction direction) { for (ElevatorCar elevator : elevators) { if (elevator.isIdle() || elevator.getCurrentDirection() == direction) { return elevator; } } return elevators.get((int) (Math.random() * elevators.size())); } } ```

### Eng Qisqa Qidirish Vaqti Birinchi Strategiyasi

```java public class ShortestSeekTimeFirstStrategy implements DispatchingStrategy { @Override public ElevatorCar selectElevator(List<ElevatorCar> elevators, int floor, Direction direction) { ElevatorCar bestElevator = null; int shortestDistance = Integer.MAX_VALUE;

for (ElevatorCar elevator : elevators) { int distance = Math.abs(elevator.getCurrentFloor() - floor); if ((elevator.isIdle() || elevator.getCurrentDirection() == direction) && distance < shortestDistance) { bestElevator = elevator; shortestDistance = distance; } } return bestElevator; } } ```

Chuqur O'rganish Mavzulari

### Hodisaga Asoslangan Lift So'rovlarini Boshqarish (Observer Pattern)

Hozirda koridor va qavat tugma so'rovlari bir xil navbatga ketma-ket qo'shiladi. Cheklovlar: - Mahkam bog'langan komponentlar. - Yuqori yuklama ostida potentsial kechikishlar.

Yechim: Koridor tugmalarini dispatch kontrolleri'dan ajratish uchun **Observer Pattern**dan foydalanish.

> **Eslatma:** Observer Pattern haqida ko'proq bilib olish uchun Qo'shimcha O'qish bo'limiga murojaat qiling.

- **Kuzatiladigan Sub'yekt:** Koridor tugmalari — bosilganda kuzatuvchi hodisasini ishga tushiradi. - **Kuzatuvchi:** Dispatch kontrolleri tugma bosish hodisalarini tinglaydi va lift ajratadi.

```java // Kuzatiladigan Sub'yekt: HallwayButtonPanel public class HallwayButtonPanel { private final int floor; private final List<ElevatorObserver> observers;

public HallwayButtonPanel(int floor) { this.floor = floor; this.observers = new ArrayList<>(); }

public void pressButton(Direction direction) { notifyObservers(direction); }

public void addObserver(ElevatorObserver observer) { observers.add(observer); }

private void notifyObservers(Direction direction) { for (ElevatorObserver observer : observers) { observer.update(floor, direction); } } }

// Kuzatuvchi Interfeysi public interface ElevatorObserver { void update(int floor, Direction direction); }

// Kuzatuvchi Amalga Oshirishi public class ElevatorDispatchController implements ElevatorObserver { @Override public void update(int floor, Direction direction) { // Qavat so'rovini boshqarish logikasi } } ```

**Afzalliklari:** - Ajratilgan arxitektura — qo'llab-quvvatlash, test va kengaytirish osonlashadi. - Band soatlarda tezroq javob — navbatni to'plab qolishni chetlab o'tadi.

### Turli Qavat To'plamlariga Xizmat Qiluvchi Liftlar

Faqat muayyan qavatlarda to'xtovchi liftlarni qo'llab-quvvatlash uchun: 1. Har bir `ElevatorCar` `Set<Integer> accessibleFloors` oladi. 2. `addFloorRequest()` navbatga qo'shishdan oldin qavatni tekshiradi. 3. Dispatching strategiyalari faqat so'ralgan qavatga yeta oladigan liftlarni ko'rib chiqadi.

```java // ElevatorCar'da — kirish mumkin qavatlar to'plamini qo'shish private final Set<Integer> accessibleFloors;

// O'zgartirilgan addFloorRequest — avval kirish imkoniyatini tekshirish public void addFloorRequest(int floor) { if (accessibleFloors.contains(floor) && !targetFloors.contains(floor)) { targetFloors.offer(floor); updateDirection(floor); } }

// Yangilangan ShortestSeekTimeFirst — kirish mumkin qavatlarni ham tekshiradi public class ShortestSeekTimeFirstStrategy implements DispatchingStrategy { @Override public ElevatorCar selectElevator(List<ElevatorCar> elevators, int floor, Direction direction) { ElevatorCar bestElevator = null; int shortestDistance = Integer.MAX_VALUE;

for (ElevatorCar elevator : elevators) { int distance = Math.abs(elevator.getCurrentFloor() - floor); if ((elevator.isIdle() || elevator.getCurrentDirection() == direction) && elevator.getAccessibleFloors().contains(floor) // Yangi tekshiruv && distance < shortestDistance) { bestElevator = elevator; shortestDistance = distance; } } return bestElevator; } } ```

**Misol:** 20 qavatli bino. 1-lift 1, 5, 10, 15, 20-qavatlarga xizmat qiladi. 2-lift barcha qavatlarga xizmat qiladi. 3-qavatdagi foydalanuvchi 'yuqori' ni bossa, 2-liftni oladi, chunki 1-lift 3-qavatda to'xtay olmaydi.

UML diagram showing HallwayButtonPanel as subject and ElevatorDispatchController as observer
Observer pattern: HallwayButtonPanel and ElevatorDispatchController
UML diagram showing ElevatorCar with accessibleFloors set and updated dispatching strategy
Elevators with accessible floors extension

Xulosa

Bu bobda biz tizimli OOD yondashuvi yordamida Lift Tizimini loyihaladik. Asosiy o'rganishlar:

- Modullilik: ElevatorSystem, ElevatorCar, ElevatorDispatch va DispatchingStrategy har biri muayyan javobgarlikka e'tibor qaratadi. - Moslashtirilishi mumkin dispatching strategiyasi algoritmlar o'rtasida oson almashinishga imkon beradi. - Observer Pattern (chuqur o'rganish) tezroq tayinlashlar uchun hodisaga asoslangan koridor chaqiruv boshqaruvini ta'minlaydi. - Kirish mumkin qavatlar qo'llab-quvvatlashi (chuqur o'rganish) mavjud dizaynni buzmagan holda kengaytirilishni namoyish etadi.

Qo'shimcha O'qish: Observer Dizayn Naqshi

Observer naqshi obuna mexanizmini belgilaydi, kuzatilayotgan ob'yekt holatini o'zgartirganda bir nechta ob'yektning avtomatik ravishda xabar olishiga imkon beradi.

**Muammo:** Yangiliklar ilovasi foydalanuvchilarga real vaqt yangilanishlarini etkazib beradi. Yangiliklar nashriyotchisini har bir foydalanuvchi bilan to'g'ridan-to'g'ri bog'lash mahkam bog'liqlikni yaratadi — qo'llab-quvvatlash va kengaytirish qiyin.

**Yechim:** Sub'yekt (yangiliklar nashriyotchisi) va kuzatuvchilar (foydalanuvchilar) o'rtasida bir-ko'p munosabat: - Sub'yekt kuzatuvchilar ro'yxatini saqlaydi va holat o'zgarganda ularni xabardor qiladi. - Kuzatuvchilar bildirishnomalar olish uchun `update()` metodini amalga oshiradi.

**Qachon ishlatish kerak:** - Bitta ob'yektdagi o'zgarishlar boshqa ob'yektlarni xabardor qilishni talab qilganda, ayniqsa xabardor qilinadigan ob'yektlar to'plami oldindan ma'lum bo'lmaganda. - Ob'yektlar faqat muayyan shartlar ostida yoki cheklangan vaqt davomida boshqa ob'yektlarni kuzatishi kerak bo'lganda.

UML class diagram illustrating the Observer design pattern with news application example
Observer design pattern class diagram
Bob 9

Oziq-Ovqat Do'koni Tizimini Loyihalash

~11 daq o'qish

Bu bobda biz oziq-ovqat do'koni tizimining dizaynini o'rganamiz. Bu tizim mahsulotlar katalogini boshqarish, narxlashni sozlash va chegirmalarni qo'llash kabi operatsiyalarni soddalashtirish uchun oziq-ovqat do'koni xodimlari uchun mo'ljallangan.

Overview of the grocery store system
Grocery Store System

Talablarni Aniqlash

Mana intervyuer tomonidan odatda beriladigan savol namunasi:

"Tasavvur qiling: siz oziq-ovqat do'konida bo'lib, aravangizni yangi mevalar, gazaklar va uy buyumlari bilan to'ldiryapsiz. Kassada kassir har bir mahsulotni skanerdan o'tkazadi va tizim buyurtmani kuzatib, barcha chegirmalarni qo'llab, yakuniy summani ko'rsatadi. Sahna ortida tizim mahsulotlar katalogini boshqaradi, zaxirani yangilab turadi va har bir tranzaksiyaning silliq va to'g'ri o'tishini ta'minlaydi. Endi bularning hammasini qiluvchi oziq-ovqat do'koni tizimini loyihalaylik."

**Talablarni aniqlash**

> **Nomzod:** Oziq-ovqat do'koni tizimi qo'llab-quvvatlashi kerak bo'lgan asosiy operatsiyalar nima? > **Intervyuer:** Tizim yuklama ishlari va kassirlar kabi do'kon xodimlariga mahsulotlar katalogini boshqarish, inventarni kuzatish va tatbiq etilgan chegirmalar bilan mijoz kassasini amalga oshirishda yordam berishi kerak.

> **Nomzod:** Kassadan o'tkazish jarayonini to'g'ri tushundim, shundaymi: kassir har bir mahsulotni skanerdan o'tkazadi yoki kodni kiritadi, tizim buyurtmani kuzatadi. U oraliq summani hisoblab, chegirmalarni qo'llab, umumiy summani yangilaydi. Barcha mahsulotlar kiritilgandan so'ng kassir yakuniy miqdorni ko'radi, to'lovni qabul qiladi va kerak bo'lsa qayta pul beradi. Keyin kvitansiya yaratiladi. To'g'rimi? > **Intervyuer:** Ha, tizimni to'g'ri tushundingiz.

> **Nomzod:** Tizim inventarni boshqarishni qanday amalga oshirishi kerak? > **Intervyuer:** Tizim barcha mahsulotlar uchun inventarni kuzatishi, yangi zaxira kelganda ko'paytirishi va kassadan o'tkazish paytida sotilgan mahsulotlar uchun avtomatik ravishda kamaytirilishi kerak.

> **Nomzod:** Tizim mahsulotlarni oziq-ovqat, ichimliklar kabi turli kategoriyalarga bo'lishlami? > **Intervyuer:** Ha, yaxshi g'oya.

> **Nomzod:** Chegirmalar bo'yicha shunday deb taxmin qilsam maqbulmi: Tizim chegirma kampaniyalarini kuzatishi kerak, ular muayyan mahsulot yoki kategoriyalarga qo'llanilishi mumkin. Agar bir xil mahsulotga bir nechta chegirma qo'llanilsa, tizim avtomatik ravishda eng katta chegirmani qo'llashi kerak. > **Intervyuer:** Ajoyib.

**Talablar**

Bu savolda bir nechta talablar mavjud, shuning uchun o'xshashlarini guruhlash boshqarish va kuzatishni osonlashtiradi. Talablar to'rt guruhga bo'linishi mumkin.

**Katalog boshqaruvi** - Adminlar katalogga mahsulotlarni qo'shishi, yangilashi va olib tashlashi mumkin. - Katalog mahsulot tafsilotlarini kuzatadi, shu jumladan nom, kategoriya, narx va shtrix-kod.

**Inventar boshqaruvi** - Yuklama xodimlari yuklama kelganda inventarni yangilashlari mumkin. - Mahsulotlar sotilganda tizim inventarni avtomatik ravishda kamaytirishi kerak.

**Kassadan o'tkazish jarayoni** - Kassirlar buyurtma yaratish uchun shtrix-kodlarni skanerdan o'tkazishlari yoki mahsulot kodlarini qo'lda kiritishlari mumkin. - Kassirlar aktiv buyurtma tafsilotlarini, shu jumladan mahsulotlar, chegirmalar va oraliq summani ko'rishlari mumkin. - Tizim mos chegirmalarni avtomatik ravishda hisoblaydi va qo'llaydi. - Kassirlar buyurtmani yakunlashlari, umumiy summani hisoblashlari, to'lovlarni amalga oshirishlari va qayta pul hisoblashlari mumkin. - Batafsil kvitansiya yaratiladi.

**Chegirma kampaniyalari** - Adminlar muayyan mahsulot yoki kategoriyalar uchun chegirma kampaniyalarini belgilashlari mumkin. - Agar mahsulotga bir nechta chegirma qo'llanilsa, tizim eng katta chegirmani tanlaydi.

Quyida funksional bo'lmagan talablar: - Tizim kassirga noto'g'ri shtrix-kodlar yoki yetarli inventar yo'qligi kabi hollarda aniq, foydalanuvchiga qulay xato xabarlarini taqdim etishi kerak. - Tizimning komponentlari (katalog, inventar, kassa, chegirmalar) butun tizimga ta'sir qilmasdan alohida modullarni yangilash yoki almashtirish imkonini beruvchi modulli bo'lishi kerak.

Asosiy Ob'yektlarni Aniqlash

Dizaynga kirishdan oldin asosiy ob'yektlarni sanab chiqish muhim.

- **Item (Mahsulot):** Oziq-ovqat do'konidagi alohida tovarni ifodalaydi, nom, shtrix-kod, kategoriya va narx kabi tafsilotlarni o'z ichiga oladi. - **Catalog (Katalog):** Barcha mahsulotlar uchun markaziy ombor vazifasini bajaradi, mahsulotlar to'plamini boshqaradi va qo'shish, yangilash, olib tashlash kabi operatsiyalarni qo'llab-quvvatlaydi. - **Inventory (Inventar):** Har bir mahsulot uchun zaxira darajalarini kuzatadi. Yangi zaxira kelganda (yuklama orqali) yoki kassadan o'tkazish paytida mahsulotlar sotilganda mavjud mahsulotlar sonini yangilaydi. - **Order (Buyurtma):** Bu ob'yekt kassadan o'tkazish jarayonini kuzatadi. U buyurtmadagi mahsulotlar, aktiv chegirmalar va oraliq hamda umumiy narxlar hisob-kitobini boshqaradi. Bu ma'lumotlar buyurtma yakunlangandan keyin kvitansiya yaratish uchun ishlatiladi. - **DiscountCampaign (Chegirma Kampaniyasi):** DiscountCampaign ob'yekti chegirma qo'llash uchun aktsiya qoidalarini belgilaydi.

Sinflar Diagrammasini Loyihalash

Asosiy ob'yektlar va ularning rollarini bilganimizdan so'ng, keyingi qadam talablarni oson qo'llab-quvvatlash mumkin bo'lgan tizimga aylantiradigan sinflar va metodlarni yaratishdir. Keling, batafsil ko'rib chiqaylik.

**Item (Mahsulot)**

Sinf diagrammasidagi birinchi komponent — `Item` sinfi, do'kondagi alohida tovarlarni ifodalaydi. U nom, shtrix-kod, kategoriya va narx kabi atributlarni inkapsuliyalaydi.

UML diagram of the Item class with name, barcode, category, and price fields
Item class diagram

Catalog, Inventory va Discount Sinflari

**Catalog (Katalog)**

`Catalog` sinfi shtrix-kod bilan noyob identifikatsiyalangan barcha mavjud mahsulotlarning tizimli ro'yxatini saqlash uchun javobgardir. U mahsulotlarni qo'shish, yangilash, olib tashlash va olish metodlarini taqdim etadi.

UML diagram of the Catalog class
Catalog class diagram
UML diagram of the Inventory class with stock management methods
Inventory class diagram

Chegirma Dizayni (Strategy + Composite Pattern)

> **Dizayn tanlovi:** Modullilik va qo'llab-quvvatlash imkoniyatini ta'minlash uchun biz statik mahsulot tafsilotlarini dinamik zaxira darajalaridan ataylab ajratdik: **Statik Ma'lumotlar (Catalog)** mahsulot metama'lumotlarini boshqaradi; **Dinamik Ma'lumotlar (Inventory)** tez-tez o'zgaradigan zaxira darajalarini boshqaradi. Bu ajratish Yagona Javobgarlik Printsipiga amal qiladi.

**DiscountCriteria**

`DiscountCriteria` interfeysi chegirma mahsulotga qo'llanilishini aniqlash uchun logikani inkapsuliyalaydi. U mahsulotga asoslangan va kategoriyaga asoslangan mezonlar kabi qo'llanilish tekshiruvlarini belgilash uchun moslashuvchan, kengaytirilishi mumkin bo'lgan doirani taqdim etadi.

- **CategoryBasedCriteria:** Mahsulot muayyan kategoriyaga tegishli ekanligini tekshirib, chegirma qo'llanilishini aniqlaydi. - **ItemBasedCriteria:** Chegirma uning noyob identifikatori orqali muayyan mahsulotga qo'llanilishini tekshiradi.

**DiscountCalculationStrategy**

`DiscountCalculationStrategy` interfeysi Strategy Pattern yordamida chegirmalarni hisoblash logikasini inkapsuliyalaydi.

- **AmountBasedStrategy:** Asl narxga qat'iy chegirma miqdorini qo'llaydi. - **PercentageBasedStrategy:** Asl narxga foizga asoslangan chegirma qo'llaydi.

> **Dizayn tanlovi:** Bu dizayn yuqori darajada kengaytirilishi mumkin, chunki yangi chegirma strategiyalarini mavjud amalga oshirishni o'zgartirmasdan muammosiz qo'shish mumkin, Ochiq/Yopiq Printsipiga amal qiladi.

**DiscountCampaign**

`DiscountCampaign` sinfi aktiv chegirma kampaniyalarini modellashtiradi. U turli hisoblash strategiyalarini inkapsuliyalash uchun Strategy Pattern'dan foydalanadi va qaysi mahsulotlar chegirmaga munosib ekanligini belgilash uchun `DiscountCriteria` interfeysidan foydalanadi.

> **Dizayn tanlovi:** Qo'llanilish logikasini (mezon) hisoblash strategiyasidan ajratib, sinf ko'proq modulli va kengaytirilishi osonlashadi.

UML diagram of DiscountCriteria interface with CategoryBasedCriteria and ItemBasedCriteria
DiscountCriteria interface and concrete classes
UML diagram of DiscountCalculationStrategy with AmountBasedStrategy and PercentageBasedStrategy
DiscountCalculationStrategy interface and concrete classes
UML diagram of DiscountCampaign with criteria and calculationStrategy fields
DiscountCampaign class diagram

Order, Receipt va Checkout Sinflari

**OrderItem (Buyurtma Elementi)**

`OrderItem` sinfi buyurtmadagi miqdori bilan birga muayyan mahsulotni ifodalaydi. U birlik narxi va miqdor asosida umumiy narxni hisoblash metodlarini inkapsuliyalaydi.

> **Dizayn tanlovy:** `OrderItem` sinfi element darajasidagi tafsilotlarni yuqori darajali buyurtmadan ajratadi, har bir mahsulotning miqdori va narx logikasining inkapsuliyalanganligini ta'minlaydi.

**Order (Buyurtma)**

`Order` sinfi kassadan o'tkazish jarayonidagi aktiv tranzaksiyani ifodalaydi. U mahsulotlar va qo'llangan chegirmalar ro'yxatini kuzatib, chegirmasiz oraliq summani va chegirmali umumiy summani hisoblash metodlarini taqdim etadi.

> **Dizayn tanlovi:** `Order` sinfi alohida mahsulot miqdorlarini boshqarishni `OrderItem`'ga topshiradi, bu javobgarliklarni aniq ajratishni ta'minlaydi.

**Receipt (Kvitansiya)**

`Receipt` sinfi yakunlangan tranzaksiyaning yakuniy yozuvi sifatida ishlaydi, buyurtma xulosasini, to'lov tafsilotlarini va qayta pulni birlashtiradi.

> **Dizayn tanlovi:** `Receipt` sinfi faqat tranzaksiya ma'lumotlarini mijozga qulay formatda taqdim etishga e'tibor qaratadi, barcha biznes logikasini `Order` va `OrderItem`'ga topshiradi.

**Checkout (Kassadan O'tkazish)**

`Checkout` sinfi kassadan o'tkazish jarayonini boshqarish logikasini inkapsuliyalaydi. U aktiv `Order` ob'yektini saqlaydi va aktiv chegirma kampaniyalarini qo'llaydi.

> **Dizayn tanlovi:** Markaziy roliga qaramay, `Checkout` sinfi yengil bo'lib qoladi, chunki javobgarliklar `Order`, `DiscountCampaign` va asosiy strategiya sinflariga topshiriladi.

UML diagram of OrderItem class with item and quantity fields
OrderItem class diagram
UML diagram of Order class with items list and appliedDiscounts map
Order class diagram
UML diagram of Receipt class
Receipt class diagram
UML diagram of Checkout class
Checkout class diagram

GroceryStoreSystem (Fasad)

`GroceryStoreSystem` sinfi tizim komponentlari (Catalog, Inventory, Checkout) bilan muloqotni soddalashtiruvchi **Fasad** vazifasini bajaradi. Yagona interfeys taqdim etib, asosiy murakkablikni yashiradi.

UML diagram of GroceryStoreSystem class
GroceryStoreSystem facade class diagram
Full UML class diagram showing all grocery store system components and their relationships
Complete Class Diagram of Grocery Store System

Kod — Oziq-Ovqat Do'koni Tizimi

**Item (Mahsulot)**

```java public class Item { private final String name; private final String barcode; private final String category; private BigDecimal price;

public Item(String name, String barcode, String category, BigDecimal price) { this.name = name; this.barcode = barcode; this.category = category; this.price = price; }

// getter va setter metodlari qisqartirish uchun tushirib qoldirildi } ```

**Catalog (Katalog)**

```java public class Catalog { // Shtrix-kodlarni mos mahsulotlarga aylantiruvchi map private final Map<String, Item> items = new HashMap<>();

public void updateItem(Item item) { items.put(item.getBarcode(), item); }

public void removeItem(String barcode) { items.remove(barcode); }

public Item getItem(String barcode) { return items.get(barcode); } } ```

**Inventory (Inventar)**

```java public class Inventory { // Shtrix-kodlarni zaxira miqdoriga aylantiruvchi map private final Map<String, Integer> stock = new HashMap<>();

public void addStock(String barcode, int count) { stock.put(barcode, stock.getOrDefault(barcode, 0) + count); }

public void reduceStock(String barcode, int count) { stock.put(barcode, stock.getOrDefault(barcode, 0) - count); }

public int getStock(String barcode) { return stock.getOrDefault(barcode, 0); } } ```

> **Amalga oshirish tanlovi:** `Inventory` sinfi shtrix-kodlarni zaxira miqdoriga aylantirishda O(1) o'rtacha holat vaqt murakkabligini ta'minlovchi `HashMap` ishlatadi.

**DiscountCampaign (Chegirma Kampaniyasi)**

```java public class DiscountCampaign { private final String discountId; private final String name; private final DiscountCriteria criteria; private final DiscountCalculationStrategy calculationStrategy;

public DiscountCampaign( String discountId, String name, DiscountCriteria criteria, DiscountCalculationStrategy calculationStrategy) { this.discountId = discountId; this.name = name; this.criteria = criteria; this.calculationStrategy = calculationStrategy; }

// Ushbu chegirma berilgan mahsulotga qo'llanilishini tekshiradi public boolean isApplicable(Item item) { return criteria.isApplicable(item); }

// Berilgan buyurtma elementi uchun chegirmali narxni hisoblaydi public BigDecimal calculateDiscount(OrderItem item) { return calculationStrategy.calculateDiscountedPrice(item.calculatePrice()); } // getter va setter metodlari qisqartirish uchun tushirib qoldirildi } ```

> **Amalga oshirish tanlovi:** `DiscountCampaign` sinfi moslashuvchan chegirma konfiguratsiyalari uchun polimorfizmdan foydalanib, bitta `DiscountCriteria` va `DiscountCalculationStrategy` saqlash uchun kompozitsiyadan foydalanadi.

**OrderItem (Buyurtma Elementi)**

```java public class OrderItem { private final Item item; private final int quantity;

public OrderItem(Item item, int quantity) { this.item = item; this.quantity = quantity; }

// Biron bir chegirmasiz ushbu buyurtma elementi uchun umumiy narxni hisoblaydi public BigDecimal calculatePrice() { return item.getPrice().multiply(BigDecimal.valueOf(quantity)); }

// Berilgan chegirma bilan ushbu buyurtma elementi uchun umumiy narxni hisoblaydi public BigDecimal calculatePriceWithDiscount(DiscountCampaign newDiscount) { return newDiscount.calculateDiscount(this); } // getter va setter metodlari qisqartirish uchun tushirib qoldirildi } ```

**Order (Buyurtma)**

```java public class Order { private final String orderId; private final List<OrderItem> items = new ArrayList<>(); private final Map<OrderItem, DiscountCampaign> appliedDiscounts = new HashMap<>(); private BigDecimal paymentAmount = BigDecimal.ZERO;

public Order() { this.orderId = String.valueOf(UUID.randomUUID()); }

public void addItem(OrderItem item) { items.add(item); }

// Chegirmasiz barcha mahsulotlarning oraliq summasini hisoblaydi public BigDecimal calculateSubtotal() { return items.stream() .map(OrderItem::calculatePrice) .reduce(BigDecimal.ZERO, BigDecimal::add); }

// Barcha qo'llangan chegirmalar bilan umumiy narxni hisoblaydi public BigDecimal calculateTotal() { return items.stream() .map(item -> { DiscountCampaign discount = appliedDiscounts.get(item); return discount != null ? item.calculatePriceWithDiscount(discount) : item.calculatePrice(); }) .reduce(BigDecimal.ZERO, BigDecimal::add); }

public void applyDiscount(OrderItem item, DiscountCampaign discount) { appliedDiscounts.put(item, discount); }

public BigDecimal calculateChange() { return paymentAmount.subtract(calculateTotal()); } // getter va setter metodlari qisqartirish uchun tushirib qoldirildi } ```

> **Amalga oshirish tanlovi:** `Order` sinfi tez O(1) mahsulot qo'shishlar uchun `ArrayList` va O(1) chegirma qidirish uchun `HashMap<OrderItem, DiscountCampaign>` ishlatadi.

**Checkout (Kassadan O'tkazish)**

```java public class Checkout { private Order currentOrder; private final List<DiscountCampaign> activeDiscounts;

public Checkout(List<DiscountCampaign> activeDiscounts) { this.activeDiscounts = activeDiscounts; startNewOrder(); }

public void startNewOrder() { this.currentOrder = new Order(); }

public BigDecimal processPayment(BigDecimal paymentAmount) { currentOrder.setPayment(paymentAmount); return currentOrder.calculateChange(); }

// Joriy buyurtmaga mahsulot qo'shadi va mos chegirmalarni qo'llaydi public void addItemToOrder(Item item, int quantity) { OrderItem orderItem = new OrderItem(item, quantity); currentOrder.addItem(orderItem);

for (DiscountCampaign newDiscount : activeDiscounts) { if (newDiscount.isApplicable(item)) { // Agar bir nechta chegirma qo'llanilsa, yuqoriroqni saqlash (past yakuniy narx) if (currentOrder.getAppliedDiscounts().containsKey(orderItem)) { DiscountCampaign existingDiscount = currentOrder.getAppliedDiscounts().get(orderItem); if (orderItem.calculatePriceWithDiscount(newDiscount) .compareTo(orderItem.calculatePriceWithDiscount(existingDiscount)) > 0) { currentOrder.applyDiscount(orderItem, newDiscount); } } else { currentOrder.applyDiscount(orderItem, newDiscount); } } } }

public Receipt getReceipt() { return new Receipt(currentOrder); }

public BigDecimal getOrderTotal() { return currentOrder.calculateTotal(); } } ```

> **Amalga oshirish tanlovi:** `Checkout` sinfi aktiv chegirmalarni saqlash uchun `ArrayList` ishlatadi, bu qo'llanilish imkoniyatini baholash va eng katta chegirmani tanlash uchun chiziqli ko'rib chiqishni (O(n)) ta'minlaydi.

**GroceryStoreSystem**

```java public class GroceryStoreSystem { private final Catalog catalog; private final Inventory inventory; private List<DiscountCampaign> activeDiscounts = new ArrayList<>(); private final Checkout checkout;

public GroceryStoreSystem() { this.catalog = new Catalog(); this.inventory = new Inventory(); this.checkout = new Checkout(activeDiscounts); }

public void addOrUpdateItem(Item item) { catalog.updateItem(item); }

public void updateInventory(String barcode, int count) { inventory.addStock(barcode, count); }

public void addDiscountCampaign(DiscountCampaign discount) { activeDiscounts.add(discount); }

public Item getItemByBarcode(String barcode) { return catalog.getItem(barcode); }

public void removeItem(String barcode) { catalog.removeItem(barcode); } } ```

Chuqur O'rganish — Moslashuvchan Chegirma Mezonlari

Joriy dizayn chegirma logikasini ikki komponentga inkapsuliyalaydi: **Mezon** (mahsulot munosibligini aniqlaydi) va **Narx Hisoblash Strategiyasi** (chegirmali narxni hisoblaydi). Lekin intervyuer murakkab kompozit chegirmalarni so'rasa nima bo'ladi?

**Bir nechta Mezonlarni Birlashtirish (Composite Pattern)**

Ichma-ich yoki birlashtirilgan mezonlarni boshqarish uchun **Composite Pattern**dan foydalanamiz. Kompozit mezonlar AND va OR kabi mantiqiy operatorlar yordamida bir nechta qoidalarni birlashtirish imkonini beradi.

> **Eslatma:** Composite Pattern haqida ko'proq bilib olish uchun Unix Fayl Qidirish bobiga murojaat qiling.

```java public class CompositeCriteria implements DiscountCriteria { private final List<DiscountCriteria> criteriaList;

public CompositeCriteria(List<DiscountCriteria> criteriaList) { this.criteriaList = new ArrayList<>(criteriaList); }

@Override public boolean isApplicable(Item item) { return criteriaList.stream().allMatch(criteria -> criteria.isApplicable(item)); }

public void addCriteria(DiscountCriteria criteria) { criteriaList.add(criteria); }

public void removeCriteria(DiscountCriteria criteria) { criteriaList.remove(criteria); } } ```

**Chegirma Hisob-kitoblarini Qatlamlash (Decorator Pattern)**

Ketma-ket chegirma hisob-kitoblarini boshqarish uchun **Decorator Pattern**dan foydalanamiz. Bir nechta hisoblash strategiyalarini o'rab, chegirmalarni muayyan tartibda qo'llashimiz mumkin: 1. Avval qat'iy chegirma qo'llaniladi. 2. Keyin qolgan narxga foizga asoslangan chegirma qo'llaniladi.

```java public class FixedDiscountDecorator implements DiscountCalculationStrategy { private final DiscountCalculationStrategy strategy; private final BigDecimal fixedAmount;

public FixedDiscountDecorator(DiscountCalculationStrategy strategy, BigDecimal fixedAmount) { this.strategy = strategy; this.fixedAmount = fixedAmount; }

@Override public BigDecimal calculateDiscountedPrice(BigDecimal originalPrice) { return strategy.calculateDiscountedPrice(originalPrice).subtract(fixedAmount); } }

public class PercentageDiscountDecorator implements DiscountCalculationStrategy { private final DiscountCalculationStrategy strategy; private final BigDecimal additionalPercentage;

public PercentageDiscountDecorator( DiscountCalculationStrategy strategy, BigDecimal additionalPercentage) { this.strategy = strategy; this.additionalPercentage = additionalPercentage; }

@Override public BigDecimal calculateDiscountedPrice(BigDecimal originalPrice) { BigDecimal baseDiscountedPrice = strategy.calculateDiscountedPrice(originalPrice); return baseDiscountedPrice.multiply( BigDecimal.ONE.subtract(additionalPercentage.divide(BigDecimal.valueOf(100)))); } } ```

Xulosa

Bu bobda biz oziq-ovqat do'koni tizimini loyihaladik. Nomzod/intervyuer dialogini orqali talablarni ro'yxatlashtirish, asosiy ob'yektlarni aniqlash, sinf diagrammasini yaratish va amalga oshirish kodini taqdim etishdan boshladik.

Eng muhim o'rganish — **javobgarliklarni aniq ajratish**: har bir komponent (Catalog, Inventory, Order, DiscountCampaign) muayyan javobgarlikka e'tibor qaratib, modulliligi va muammosiz integratsiyani ta'minlaydi.

Chuqur o'rganishda biz Composite va Decorator patternlaridan foydalanib, kompozit chegirmalar va bir nechta hisoblash strategiyalarini qatlamlash kabi ilg'or mavzularni o'rganamiz. Bu kengaytirishlar abstraksiya va kengaytirilishning murakkab real stsenariylarni qanday boshqarishini namoyish etadi.

Qo'shimcha O'qish — Decorator Dizayn Naqshi

**Decorator dizayn naqshi**

Decorator — asl ob'yektning kodini o'zgartirmasdan, uni qo'shimcha funksionallikni taqdim etuvchi boshqa ob'yektga o'rab, ob'yektga yangi xatti-harakatlarni qo'shish imkonini beruvchi strukturaviy dizayn naqshi.

Oziq-ovqat do'koni tizimida biz `DiscountCalculationStrategy` ob'yektlarini `FixedDiscountDecorator` va `PercentageDiscountDecorator`'ga o'rab, bir nechta chegirma hisob-kitoblarini qatlamlash uchun Decorator naqshidan foydalandik. Bu asosiy chegirma strategiyalarini o'zgartirmasdan chegirmalarni ketma-ket qo'llash imkonini beradi.

**Muammo**

Matn muharriri foydalanuvchilar matnni qalin, kursiv yoki tagiga chizish bilan formatlashiga imkon beradi deb tasavvur qiling. Kichik sinflar kombinatsiyalarining portlashiga (BoldText, BoldItalicText...) olib keladi va yangi uslublarni qo'shishni qiyinlashtiradi.

**Yechim**

Decorator Pattern Text sinfi bilan bir xil interfeysni amalga oshiradigan va Text ob'yektini o'raydigan dekorator sinflarni yaratadi. Dekoratorlar uslublarni birlashtirish uchun bir-biriga qalinlashtirilishi mumkin (qalin + kursiv), Text sinfini o'zgartirmasdan moslashuvchanlikni ta'minlaydi.

**Qachon ishlatish kerak**

- Ish vaqtida ob'yektlarga dinamik ravishda kodini o'zgartirmasdan xususiyatlar yoki xatti-harakatlar qo'shish kerak bo'lganda. - Kichik sinflar juda ko'p xususiyat kombinatsiyalariga olib kelganda, kompozitsiya oddiyroq alternativ hisoblanadi.

UML diagram showing Decorator pattern with Text interface, PlainText, BoldDecorator, and ItalicDecorator
Decorator pattern — Text interface and concrete classes
Bob 10

Tic-Tac-Toe O'yinini Loyihalash

~8 daq o'qish

Bu bobda biz Tic-Tac-Toe o'yinining ob'yektga yo'naltirilgan dizaynini o'rganamiz. Maqsad — ikki o'yinchi navbat bilan virtual taxtada o'z belgilarini qo'yib o'ynay oladigan interaktiv platforma yaratishdir. Biz o'yin taxtasi, o'yinchi harakatlari kuzatuvi, natijani aniqlash va o'yinchi reytinglarini boshqarish uchun ball tracker kabi asosiy komponentlarni loyihalashga e'tibor qaratamiz.

**Tic-Tac-Toe Qanday Ishlaydi:** Tic-Tac-Toe 3×3 to'rda o'ynaladigan klassik ikki o'yinchili o'yin. Har bir o'yinchi belgi tanlaydi ("X" yoki "O") va bo'sh katakka joylashtirish uchun navbat bilan turadi. Maqsad — uchta bir xil belgi gorizontal, vertikal yoki diagonal ravishda qatorga to'g'ri keltirishdir. O'yin o'yinchi bu maqsadga erishsa g'alaba bilan, to'qqiz katakning barchasi to'lsa va g'olib bo'lmasa durrang bilan tugaydi.

Talablarni Aniqlash

Mana intervyuer tomonidan odatda beriladigan savol namunasi:

"Tasavvur qiling: siz do'stingiz bilan Tic-Tac-Toe o'ynash uchun o'tirasiz. Har biringiz belgi tanlaysiz (masalan, "X" yoki "O") va taxtaga belgini qo'yish uchun navbat bilan galma-galdan yurasiz. Har bir harakatdan keyin o'yin kimdir g'alaba qozondimi yoki taxta to'ldimi, ya'ni durrang ekanligini tekshiradi. Sahna ortida o'yin harakatlaringizni kuzatadi, g'alabalarni aks ettiruvchi hisobni yangilaydi va kelajakdagi o'yinlar uchun o'yinchi reytinglarini saqlaydi. Bularning hammasini boshqaradigan Tic-Tac-Toe o'yini tizimini loyihalaylik."

> **Nomzod:** O'yin turli taxta o'lchamlarini qo'llab-quvvatlaydimi? > **Intervyuer:** Yo'q, soddalik uchun standart 3×3 taxtada qolaylik.

> **Nomzod:** Tizim g'alaba, mag'lubiyat va durrang kabi natijalarni qanday boshqarishi kerak? > **Intervyuer:** Tizim g'alaba naqshlarini aniqlashi va o'yinchilarga natijani bildirishi kerak: g'alaba, durrang yoki davom etmoqda.

> **Nomzod:** O'yin o'yinchi reytinglarini kuzatishi kerakmi? > **Intervyuer:** Ha, o'yin o'yin natijalariga (g'alaba, mag'lubiyat yoki durrang) asoslanib o'yinchi reytinglarini yangilaydigan ball tracker'ni saqlashi kerak.

> **Nomzod:** O'yin noto'g'ri harakatlarni qanday boshqaradi? > **Intervyuer:** Agar o'yinchi band yoki noto'g'ri pozitsiyaga harakat qilishga urinsa, uni xabardor qilib, yangi harakat uchun so'rash kerak.

**Talablar**

- O'yin 3×3 taxtada o'ynaladi. - Tizim o'yin holatini aniqlaydi: g'alaba (uchta bir xil belgi qatorga tizilgan), durrang (g'alibsiz to'liq taxta) yoki davom etmoqda. - Ball tracker o'yinchi ko'rsatkichlarini qayd etadi, g'alabalarga asoslanib reytinglarni yangilaydi va reytinglar yoki top o'yinchilar kabi so'rovlarni qo'llab-quvvatlaydi. - Noto'g'ri harakatlar (masalan, band katakka belgi qo'yish) qayta ko'rib chiqish uchun xabardorlik bilan rad etiladi.

**Funksional bo'lmagan talablar:** - Foydalanuvchi interfeysi intuitiv bo'lishi, noto'g'ri harakatlar va o'yin natijalari uchun aniq fikr-mulohaza taqdim etishi kerak. - Tizim katta arxitektura o'zgartirishlarisiz kelajakdagi kengaytirishlarni (turli taxta o'lchamlari, o'yin rejimlari) qo'llab-quvvatlashi kerak.

Asosiy Ob'yektlarni Aniqlash

- **Board (Taxta):** 3×3 o'yin to'rini modellashtiradi. To'rni yangilashni, qator, ustun va diagonallarni tekshirib g'olibni aniqlashtirni va taxta to'lganligini aniqlashni boshqaradi. - **Player (O'yinchi):** O'yinni o'ynayotgan alohida shaxsni ifodalaydi. - **Game (O'yin):** Navbat almashishni muvofiqlashtiruvchi, harakatlarni tasdiqlash va o'yin holatini kuzatuvchi markaziy sub'yekt. - **ScoreTracker (Ball Tracker):** O'yinlar bo'ylab o'yinchi reytinglarini kuzatadi, natijalarga asoslanib ularni yangilaydi.

> **Dizayn tanlovi:** `Game` sinfi ortiqcha yuklanib ketishi mumkin. Uni boshqarish uchun `Board`ga to'rni boshqarishni, `ScoreTracker`ga o'yinchi reytinglarini boshqarishni topshiramiz. Bu modullilik qo'llab-quvvatlash va kengaytirilishni yaxshilaydi.

Sinflar Diagrammasini Loyihalash

**Game (O'yin)**

`Game` sinfi markaziy koordinator. U o'yin jarayonini boshqaradi, komponentlarni ishga tushiradi, navbatlarni boshqaradi va natijalarni aniqlaydi. `ScoreTracker` o'yinchi ko'rsatkichlarini kuzatish uchun, `Board` to'rni boshqarish uchun, `Player` sinfi esa holatsiz (saqlangan g'alaba sonlari yo'q) bo'lib qoladi.

UML diagram of the Game class with board, scoreTracker, players, and currentPlayerIndex
Game class diagram

Board, ScoreTracker, Move va Player Sinflari

**Board (Taxta)**

`Board` sinfi 3×3 o'yin to'rini `Player` ob'yektlarining ikki o'lchamli massivi sifatida ifodalaydi. Harakat haqiqiyligini ta'minlaydi, qator/ustun/diagonal tekshiruv orqali g'oliblarni aniqlaydi va to'rni qayta tiklashni qo'llab-quvvatlaydi.

> **Dizayn tanlovi:** G'alaba tekshiruvi logikasi `Board`da joylashishi kerak (not `Game`), Yagona Javobgarlik Printsipiga amal qilib — Board to'r bog'liq qoidalarga egalik qiladi.

**ScoreTracker (Ball Tracker)**

`ScoreTracker` g'alaba sonlarining markazlashtirilgan `HashMap<Player, Integer>`'ni saqlaydi. Reytinglar `Player` sinfidan ataylab ajratilgan, chunki ular kontekstual (boshqalarga nisbatan), o'yinlar o'ynalishi bilan o'zgaradi va ilg'or tizimlarda rivojlanishi mumkin (masalan, turli ligalar).

**Move (Harakat)**

`Move` sinfi `row`, `column` va `player`'ni bitta ma'lumotlar strukturasiga birlashtiradi, ularni alohida parametrlar sifatida uzatish o'rniga kod o'qilishini yaxshilaydi.

**Player (O'yinchi)**

`Player` sinfi `name` va `symbol`'ni inkapsuliyalaydi. Harakat tasdiqlash va reyting yangilash SRP'ni hurmat qilish maqsadida ataylab chiqarib tashlangan — `Board` harakatlarni tasdiqlaydi, `ScoreTracker` reytinglarni boshqaradi.

UML diagram of the Board class with 2D grid and win-checking methods
Board class diagram
UML diagram of ScoreTracker with playerRatings HashMap
ScoreTracker class diagram
UML diagram of the Move class with colIndex, rowIndex, and player fields
Move class diagram
UML diagram of the Player class with name and symbol attributes
Player class diagram

To'liq Sinflar Diagrammasi

Quyida Tic-Tac-Toe o'yinining to'liq sinflар diagrammasi keltirilgan.

Full UML class diagram showing Game, Board, Player, ScoreTracker, and Move relationships
Complete Class Diagram of Tic-Tac-Toe

Kod — Tic-Tac-Toe O'yini

**Game (O'yin)**

```java public class Game { private final Board board; private final ScoreTracker scoreTracker; private Player[] players; private int currentPlayerIndex;

public Game(Player playerX, Player playerY) { board = new Board(); scoreTracker = new ScoreTracker(); startNewGame(playerX, playerY); }

public void startNewGame(Player playerX, Player playerY) { board.reset(); players = new Player[] {playerX, playerY}; currentPlayerIndex = 0; }

public void makeMove(int colIndex, int rowIndex, Player player) { if (getGameStatus().equals(GameCondition.ENDED)) { throw new IllegalStateException("o'yin tugadi"); } if (players[currentPlayerIndex] != player) { throw new IllegalArgumentException("joriy o'yinchi emas"); } if (board.getPlayerAt(colIndex, rowIndex) != null) { throw new IllegalArgumentException("taxta pozitsiyasi band"); } board.updateBoard(colIndex, rowIndex, player); final Move newMove = new Move(colIndex, rowIndex, player); currentPlayerIndex = (currentPlayerIndex + 1) % players.length; if (getGameStatus().equals(GameCondition.ENDED)) { scoreTracker.reportGameResult(players[0], players[1], board.getWinner()); } }

public GameCondition getGameStatus() { Optional<Player> winner = board.getWinner(); if (winner.isPresent()) { return GameCondition.ENDED; } return board.isFull() ? GameCondition.ENDED : GameCondition.IN_PROGRESS; }

public Player getCurrentPlayer() { return players[currentPlayerIndex]; }

public ScoreTracker getScoreTracker() { return scoreTracker; } } ```

> **Amalga oshirish tanlovi:** `Game` sinfi `GameCondition` enum (IN_PROGRESS yoki ENDED) bilan holat mashina kabi yondashuvdan foydalanadi, bir vaqtda faqat bitta o'yinchi harakat qilishini va g'alaba yoki durrang bo'lganda o'yin to'xtashini ta'minlaydi.

**Board (Taxta)**

```java public class Board { private final Player[][] grid = new Player[3][3];

public void updateBoard(int colIndex, int rowIndex, Player player) { if (grid[colIndex][rowIndex] == null) { grid[colIndex][rowIndex] = player; } }

public Optional<Player> getWinner() { // Qatorda uchta ketma-ket belgi borligini tekshirish for (int i = 0; i < grid.length; i++) { Player first = grid[i][0]; if (first != null && Arrays.stream(grid[i]).allMatch(p -> p == first)) { return Optional.of(first); } }

// Ustunda uchta ketma-ket belgi borligini tekshirish for (int j = 0; j < grid[0].length; j++) { final Player first = grid[0][j]; int finalJ = j; if (first != null && Arrays.stream(grid).allMatch(row -> row[finalJ] == first)) { return Optional.of(first); } }

// Asosiy diagonalni tekshirish (yuqori chap dan pastgi o'ng) Player topLeft = grid[0][0]; if (topLeft != null && IntStream.range(0, grid.length).allMatch(i -> grid[i][i] == topLeft)) { return Optional.of(topLeft); }

// Anti-diagonalni tekshirish (yuqori o'ng dan pastgi chap) Player topRight = grid[0][grid[0].length - 1]; if (topRight != null && IntStream.range(0, grid.length) .allMatch(i -> grid[i][grid[0].length - 1 - i] == topRight)) { return Optional.of(topRight); }

return Optional.empty(); }

public boolean isFull() { return Arrays.stream(grid).flatMap(Arrays::stream).noneMatch(Objects::isNull); }

public void reset() { for (Player[] players : grid) { Arrays.fill(players, null); } }

public Player getPlayerAt(int colIndex, int rowIndex) { return grid[colIndex][rowIndex]; } } ```

> **Amalga oshirish tanlovi:** `Board` to'g'ridan-to'g'ri fazoviy xaritalash va O(1) pozitsiya kirishi uchun 2D massiv (`Player[][]`) ishlatadi.

**Player (O'yinchi)**

```java public class Player { private final String name; private final char symbol;

public Player(String name, char symbol) { this.name = name; this.symbol = symbol; }

public String getName() { return name; }

public char getSymbol() { return symbol; } } ```

**ScoreTracker (Ball Tracker)**

```java class ScoreTracker { private HashMap<Player, Integer> playerRatings = new HashMap<>();

// Oddiy g'alaba soni tizimi: g'olib +1, mag'lub -1, durrang o'zgarishsiz public void reportGameResult(Player player1, Player player2, Optional<Player> winningPlayer) { if (winningPlayer.isPresent()) { Player winner = winningPlayer.get(); Player loser = player1 == winner ? player2 : player1; playerRatings.putIfAbsent(winner, 0); playerRatings.put(winner, playerRatings.get(winner) + 1); playerRatings.putIfAbsent(loser, 0); playerRatings.put(loser, playerRatings.get(loser) - 1); } }

public Map<Player, Integer> getTopPlayers() { return playerRatings.entrySet().stream() .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())) .map(Map.Entry::getKey) .collect(Collectors.toMap(player -> player, player -> playerRatings.get(player))); }

public int getRank(Player player) { List<Player> sortedPlayers = playerRatings.entrySet().stream() .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())) .map(Map.Entry::getKey) .collect(Collectors.toList()); return sortedPlayers.indexOf(player) + 1; } } ```

> **Amalga oshirish tanlovi:** `HashMap<Player, Integer>` tez-tez ball yangilanishlari va reyting so'rovlari uchun O(1) o'rtacha holat qidirish va yangilash imkonini beradi.

Chuqur O'rganish — Harakatni Bekor Qilish Funksiyasi (Memento Pattern)

**Tic-Tac-Toe'da harakatni bekor qilish funksiyasini amalga oshirish**

**1-qadam: Harakat tarixini kuzatish**

Har safar o'yinchi harakat qilganda, biz o'sha `Move` ob'yektini (`rowIndex`, `colIndex` va `player` bilan allaqachon loyihalangan) saqlaymiz.

**2-qadam: Harakatlarni Stack bilan Saqlash**

Harakatlar LIFO tartibida sodir bo'lganligi sababli, `ArrayDeque<Move>` ishlatamiz. Harakat qilinganda uni qo'shamiz. Bekor qilish so'ralganda, eng so'nggi harakatni olib, taxtani qaytaramiz.

```java class MoveHistory { private final ArrayDeque<Move> history = new ArrayDeque<>();

public void recordMove(Move move) { history.push(move); }

public Move undoMove() { return history.pop(); }

public void clearHistory() { history.clear(); } } ```

**3-qadam: Taxta Holatini Qaytarish**

```java public void makeMove(int colIndex, int rowIndex, Player player) { if (getGameStatus().equals(GameCondition.ENDED)) { throw new IllegalStateException("o'yin tugadi"); } if (players[currentPlayerIndex] != player) { throw new IllegalArgumentException("joriy o'yinchi emas"); } if (board.getPlayerAt(colIndex, rowIndex) != null) { throw new IllegalArgumentException("taxta pozitsiyasi band"); } board.updateBoard(colIndex, rowIndex, player); final Move newMove = new Move(colIndex, rowIndex, player); moveHistory.recordMove(newMove); currentPlayerIndex = (currentPlayerIndex + 1) % players.length; if (getGameStatus().equals(GameCondition.ENDED)) { scoreTracker.reportGameResult(players[0], players[1], board.getWinner()); } }

public void undoMove() { if (getGameStatus().equals(GameCondition.ENDED)) { throw new IllegalStateException("o'yin tugadi va g'olib allaqachon e'lon qilindi"); } final Move lastMove = moveHistory.undoMove();

if (currentPlayerIndex == 0) { currentPlayerIndex = players.length - 1; } else { currentPlayerIndex--; }

board.updateBoard(lastMove.getColIndex(), lastMove.getRowIndex(), null); } ```

**Memento Pattern**

Bu **Memento Pattern**ning mohiyati — amalga oshirish tafsilotlarini oshkor qilmasdan oldingi holatni saqlash va tiklash imkonini beruvchi xatti-harakat dizayn naqshi.

- **Memento:** `Move` sinfi — bitta harakat holatini saqlaydi. - **Caretaker:** `MoveHistory` sinfi — `Move` ob'yektlari stackini saqlaydi va `undoMove()` taqdim etadi. - **Originator:** `Game` sinfi — `Move` ob'yektlarini yaratadi va holatni tiklash uchun `undoMove()` ishlatadi.

> **Eslatma:** Potentsial muammo — xotira yuklamasi. Tic-Tac-Toe'da bu minimal, lekin kattaroq holatlarga ega murakkabroq o'yinlarda har bir mementoni saqlash to'siqqа aylanishi mumkin.

UML diagram of MoveHistory class with ArrayDeque history stack
MoveHistory class diagram
UML diagram showing Memento pattern with Game (Originator), Move (Memento), and MoveHistory (Caretaker)
Undo functionality using the Memento Pattern

Xulosa

Bu bobda biz Tic-Tac-Toe o'yinini loyihaladik. Nomzod/intervyuer dialogini orqali talablarni to'pladik, asosiy ob'yektlarni aniqladik, sinf diagrammasini loyihaladik va asosiy komponentlarni amalga oshirdik.

Asosiy o'rganish — **modullilik va aniq javobgarliklarni ajratish**ning ahamiyati: `Board`, `Game`, `Player` va `ScoreTracker` har biri muayyan javobgarlikka e'tibor qaratadi.

Chuqur o'rganishda biz harakatni bekor qilish funksiyasi uchun **Memento Pattern**ni o'rganib, o'yinchilarga o'yin holati yaxlitligini saqlab, harakatlarni qaytarish imkonini beramiz.

Bob 11

Blackjack O'yinini Loyihalash

~10 daq o'qish

Bu bobda biz Blackjack o'yinining ("21" deb ham ataladi) ob'yektga yo'naltirilgan dizaynini muhokama qilamiz. Blackjack — maqsad 21 ga yig'iluvchi yoki iloji boricha yaqin, lekin undan oshib ketmaslik bo'lgan qo'l kartasini yig'ish bo'lgan mashhur karta o'yini. O'yin strategiya (qachon karta olish yoki to'xtash kerakligini hal qilish) va omadning (qanday kartalar olasiz) uyg'unligidan iborat, bu uni o'ziga jalb qiluvchi va ikonik kazino o'yiniga aylantiradi.

Overview of the Blackjack game design
Blackjack Game

Talablarni Aniqlash

> **Eslatma:** Blackjack'da turli qoidalar mavjud (masalan, soft 17, ikki baravar ko'paytirish, bo'lish). Bu bob soddalashtirilgan standart Blackjack o'yinining texnik dizayniga e'tibor qaratadi.

> **Nomzod:** O'yinni bir nechta o'yinchini qo'llab-quvvatlash uchun loyihalashim kerakmi yoki faqat dilerga qarshi bitta o'yinchi uchunmi? > **Intervyuer:** O'yin bir nechta o'yinchini qo'llab-quvvatlashi kerak.

> **Nomzod:** O'yinchi o'z navbatini o'taganidan keyin nima bo'ladi? > **Intervyuer:** Har bir o'yinchi o'z navbatini o'taganidan keyin ("karta ol" yoki "to'xta"), o'yin barcha o'yinchilar to'xtadimi yoki raqamdan oshib ketdimi tekshiradi. Keyin o'yin qo'l qiymatlarini taqqoslab g'olibni aniqlaydi va stavkalarni tugatadi.

> **Nomzod:** Diler karta olish yoki to'xtash uchun muayyan qoidalarga amal qilishi kerakmi? > **Intervyuer:** Ha, diler kamida 17 ga yetguncha karta olishi, keyin to'xtashi kerak.

> **Nomzod:** Stavkalar qanday boshqariladi? > **Intervyuer:** O'yinchilar kartalar tarqatilishidan oldin stavka qo'yadilar. G'oliblar stavkalariga teng to'lov oladilar (1:1 va asl stavka qaytariladi). Raqamdan oshib ketgan o'yinchilar stavkalarini yo'qotadilar.

**Talablar** - O'yin bir nechta o'yinchi va dilerni qo'llab-quvvatlaydi. - O'yinchilarga boshida ikkitadan karta tarqatiladi. - O'yinchilar "karta ol" (karta so'rash) yoki "to'xta" (qo'lni saqlash) qila olishadi. - Tuzerlar 1 yoki 11 sifatida baholanib, o'yinchining qo'lini optimallashtiriladi. - Barcha o'yinchilar harakatidan so'ng diler 17 ga yetguncha karta oladi, keyin to'xtaydi. O'yin g'oliblarni aniqlaydi va stavkalarni tugatadi. - G'oliblar 1:1 to'lov oladi; raqamdan oshib ketgan o'yinchilar stavkalarini yo'qotadi.

Faoliyat Diagrammasi

Faoliyat diagrammasi o'yin jarayonini vizuallashtiradi, karta tarqatishdan g'olibni aniqlashgacha har bir harakatni, qarorni va o'tishni o'z ichiga oladi — o'yinchi raqamdan oshib ketishi yoki diler 17 ga yetguncha karta olishi kabi yo'llar bilan.

Activity diagram showing game flow from betting through dealing, player turns, dealer turn, and winner determination
Activity Diagram of Blackjack Game

Asosiy Ob'yektlarni Aniqlash

- **BlackJackGame:** Boshidan oxirigacha umumiy jarayonni boshqaruvchi markaziy sub'yekt — kartalar tarqatish, o'yinchi harakatlarini kuzatish va g'oliblarni aniqlash. - **Player (O'yinchi):** Ikki amalga oshirishi bo'lgan interfeys: `RealPlayer` (stavkalar va balansni kuzatadi) va `DealerPlayer` (17 gacha karta oladi, stavka yo'q). - **Hand (Qo'l):** O'yinchi ushlab turgan kartalarni boshqaradi va barcha mumkin bo'lgan qiymatlarni hisoblaydi — Tuzerni boshqarish uchun muhim (1 yoki 11). - **Deck (Qoda):** 52 kartali to'plamni boshqaradi, aralashtiradi va olishda kartalar beradi. - **Card (Karta):** `Rank` va `Suit` enum'lari bilan belgilangan o'zgarmas sub'yekt.

Sinflar Diagrammasini Loyihalash

**Card (Karta)**

`Card` sinfi rank va suit saqlaydigan o'zgarmas qurilma birigidir. U `Rank`dan qiymatlarni olish uchun `getRankValues()` ishlatadi — Tuzer uchun ikkita mumkin bo'lgan qiymat (1 yoki 11) bo'lganligi sababli butun sonlar ro'yxatini qaytaradi.

> **Dizayn tanlovi:** Bir nechta qoda yoki o'yin variantlarida qayta foydalanish imkonini berish uchun alohida sub'yekt sifatida loyihalangan.

**Rank va Suit enum'lari**

Enum'lar ideal: type-safe, o'qilishi oson va qo'llab-quvvatlash qulay. `Rank` karta qiymatlarini saqlaydi (2–10 sonlar nominal qiymatida, yuzdagi kartalar = 10, Tuzer = 1 yoki 11). `Suit` Qo'ng'iroqlar, Olmoslar, Xochlar, Pikalar'ni ro'yxatlaydi.

> **Dizayn tanlovi:** Satrlar (validatsiya kerak va noqulay konvertatsiyalar) yoki butun sonlar (xatoga moyil, aniqlik yo'q) ustidan enum'lar. Aniq qiymatlar va nomlangan konstantalar uchun enum'lar aniq g'olibdir.

**Deck (Qoda)**

Standart 52 kartali qodani boshqaradi: aralashtirish, chiqarish, qolgan kartalarni sanash va yangi raundlar uchun qayta tiklash.

UML diagram of the Card class with rank and suit fields
Card class diagram
UML diagram of Rank enum (with values array) and Suit enum
Rank and Suit enumerations
UML diagram of Deck class with card list, shuffle, draw, and reset methods
Deck class diagram

Player, Hand va BlackJackGame Sinflari

**Player (O'yinchi)**

`Player` interfeysi barcha ishtirokchilar uchun asosiy sxema bo'lib xizmat qiladi. `RealPlayer` nom, qo'l, stavka va balansni kuzatadi. `DealerPlayer`'da stavka yoki balans yo'q — faqat 17 gacha karta oladi.

> **Dizayn tanlovi:** Interfeys asosidagi dizayn umumiy xatti-harakatlarni abstrakt qiladi, yangi o'yinchi turlari uchun kengaytirilishni oshiradi.

**Hand (Qo'l)**

Kartalarni va barcha mumkin bo'lgan qo'l summalarini boshqaradi. Tuzerlarni 1 yoki 11 sifatida `SortedSet<Integer>` barcha mumkin bo'lgan qiymatlar orqali boshqaradi. Metodlar: `addCard()`, `getCards()`, `getPossibleValues()`, `clear()`, `isBust()`.

> **Dizayn tanlovi:** `Hand`'ni `Player`'dan alohida saqlash SRP'ni ta'minlaydi — Hand kartalar va qiymatlarni boshqaradi, Player stavkalar va balansni boshqaradi.

**BlackJackGame**

O'yinchilar, diler, qoda, navbatlar va o'yin qoidalarini boshqaruvchi markaziy orkestrtor.

UML diagram of Player interface and its concrete implementations
Player interface with RealPlayer and DealerPlayer
UML diagram of Hand class with handCards list and possibleValues SortedSet
Hand class diagram
UML diagram of BlackJackGame class with deck, players, dealer, and turn management
BlackJackGame class diagram
Full UML class diagram showing all Blackjack components and their relationships
Complete Class Diagram of Blackjack

Kod — Blackjack

**Card, Rank va Suit**

```java public class Card { public final Rank rank; public final Suit suit;

public Card(Rank rank, Suit suit) { this.rank = rank; this.suit = suit; }

public int[] getRankValues() { return rank.getRankValues(); } } ```

```java public enum Rank { ACE(new int[] {1, 11}), TWO(new int[] {2}), THREE(new int[] {3}), FOUR(new int[] {4}), FIVE(new int[] {5}), SIX(new int[] {6}), SEVEN(new int[] {7}), EIGHT(new int[] {8}), NINE(new int[] {9}), TEN(new int[] {10}), JACK(new int[] {10}), QUEEN(new int[] {10}), KING(new int[] {10});

private final int[] rankValues;

Rank(int[] rankValues) { this.rankValues = rankValues; }

public int[] getRankValues() { return this.rankValues; } }

public enum Suit { HEARTS, SPADES, CLUBS, DIAMONDS } ```

> **Eslatma:** Tuzer boshidan `[1, 11]` bilan belgilangan (11 dan boshlab va sozlash emas). Bu `Hand`ga barcha mumkin bo'lgan summalarni oldindan hisoblash imkonini beradi, bir nechta Tuzerni samarali boshqaradi.

**Deck (Qoda)**

```java public class Deck { int nextCardIndex = 0; List<Card> cards;

public Deck() { initializeDeck(); }

private void initializeDeck() { cards = new ArrayList<>(); for (Suit suit : Suit.values()) { for (Rank rank : Rank.values()) { cards.add(new Card(rank, suit)); } } nextCardIndex = 0; }

public void shuffle() { Collections.shuffle(cards, new Random(System.currentTimeMillis())); }

public Card draw() { if (isEmpty() || nextCardIndex >= cards.size()) { throw new IllegalStateException("Qodada karta qolmagan"); } Card drawCard = cards.get(nextCardIndex); nextCardIndex++; return drawCard; }

public int getRemainingCardCount() { return cards.size() - nextCardIndex; }

public boolean isEmpty() { return getRemainingCardCount() == 0; }

public void reset() { nextCardIndex = 0; } } ```

> **Amalga oshirish tanlovi:** Chiqarilgan kartalarni olib tashlash (O(n) siljish) o'rniga, qoda `nextCardIndex` bilan pozitsiyani kuzatadi. Chiqarish O(1) bo'ladi.

**Hand (Qo'l)**

```java public class Hand { final List<Card> handCards = new ArrayList<>(); final SortedSet<Integer> possibleValues = new TreeSet<>();

public void addCard(Card card) { if (card == null) { throw new IllegalArgumentException("Qo'lga null karta qo'shib bo'lmaydi"); } handCards.add(card);

if (possibleValues.isEmpty()) { for (int value : card.getRankValues()) { possibleValues.add(value); } } else { SortedSet<Integer> newPossibleValue = new TreeSet<>(); for (int value : possibleValues) { for (int cardValue : card.getRankValues()) { newPossibleValue.add(value + cardValue); } } possibleValues.clear(); possibleValues.addAll(newPossibleValue); } }

public List<Card> getCards() { return Collections.unmodifiableList(handCards); }

public SortedSet<Integer> getPossibleValues() { return Collections.unmodifiableSortedSet(possibleValues); }

public void clear() { handCards.clear(); possibleValues.clear(); }

// Barcha mumkin bo'lgan qo'l qiymatlari 21 dan oshib ketganini tekshiradi public boolean isBust() { if (possibleValues.isEmpty()) { return false; } return possibleValues.first() > 21; } } ```

> **Ma'lumotlar strukturasi tanlovi:** `SortedSet` (TreeSet) saralangan qiymatlarni saqlaydi, `isBust()` uchun O(log n) kiritish va O(1) `first()` kirishni ta'minlaydi. `HashSet` O(1) kiritish, lekin minimumni topish uchun O(n) bo'lardi.

**Player, RealPlayer, DealerPlayer**

```java public interface Player { void bet(int bet); void loseBet(); void returnBet(); void payout(); boolean isBust(); Hand getHand(); int getBalance(); String getName(); int getBet(); }

public class RealPlayer implements Player { private final String name; private final Hand hand; private final int bet; private final int balance;

public RealPlayer(String name, int startBalance) { this.name = name; this.hand = new Hand(); this.bet = 0; this.balance = startBalance; }

@Override public void bet(int bet) { if (bet > balance) { throw new IllegalArgumentException("Stavka balansdan katta"); } this.bet = bet; this.balance -= bet; }

@Override public void loseBet() { this.bet = 0; }

@Override public void returnBet() { this.balance += bet; this.bet = 0; }

@Override public void payout() { this.balance += bet * 2; // Stavkani va teng miqdorni qaytarish this.bet = 0; } }

public class DealerPlayer implements Player { private final String name = "Diler"; private final Hand hand;

public DealerPlayer() { this.hand = new Hand(); }

// Stavka boshqaruv metodlari (bet, loseBet, returnBet) Diler uchun no-op @Override public void payout() { // Diler to'lov olmaydi } } ```

**BlackJackGame**

```java public class BlackJackGame { private final Deck deck = new Deck(); private final List<Player> players = new ArrayList<>(); protected final Player dealer = new DealerPlayer(); private Player currentPlayer = null; Map<Player, Action> playerTurnStatusMap = new HashMap<>(); GamePhase currentPhase = GamePhase.STARTED;

public BlackJackGame(List<Player> players) { for (Player player : players) { if (player == null) throw new IllegalArgumentException(); this.players.add(player); this.playerTurnStatusMap.put(player, null); } this.playerTurnStatusMap.put(dealer, null); deck.shuffle(); }

public Player getNextEligiblePlayer() { if (currentPlayer != null && !Action.STAND.equals(playerTurnStatusMap.get(currentPlayer)) && !currentPlayer.isBust()) { return currentPlayer; } if (currentPlayer == null) { for (Player player : players) { if (!Action.STAND.equals(playerTurnStatusMap.get(player)) && !player.isBust()) { currentPlayer = player; return currentPlayer; } } } int currentPlayerIndex = players.indexOf(currentPlayer); for (int i = currentPlayerIndex + 1; i < players.size(); i++) { Player player = players.get(i); if (!Action.STAND.equals(playerTurnStatusMap.get(player)) && !player.isBust()) { currentPlayer = player; return currentPlayer; } } return null; }

protected void dealerTurn() { while (dealer.getHand().getPossibleValues().last() < 17) { dealer.getHand().addCard(deck.draw()); } playerTurnStatusMap.put(dealer, Action.STAND); checkGameEndCondition(); }

public void dealInitialCards() { if (!GamePhase.BET_PLACED.equals(currentPhase)) { throw new IllegalStateException("Kartalar tarqatilishidan oldin barcha o'yinchilar stavka qo'yishi kerak"); } for (Player player : players) { player.getHand().addCard(deck.draw()); } dealer.getHand().addCard(deck.draw()); for (Player player : players) { player.getHand().addCard(deck.draw()); } dealer.getHand().addCard(deck.draw()); currentPhase = GamePhase.INITIAL_CARD_DRAWN; }

public void hit(Player player) { if (Action.STAND.equals(playerTurnStatusMap.get(player))) { throw new IllegalStateException("O'yinchi allaqachon to'xtadi"); } if (player.isBust()) { throw new IllegalStateException("O'yinchi allaqachon raqamdan oshib ketdi"); } player.getHand().addCard(deck.draw()); playerTurnStatusMap.put(player, Action.HIT); }

public void stand(Player player) { if (Action.STAND.equals(playerTurnStatusMap.get(player))) { throw new IllegalStateException("O'yinchi allaqachon to'xtadi"); } playerTurnStatusMap.put(player, Action.STAND); }

private void checkGameEndCondition() { boolean allPlayersDone = players.stream() .allMatch(p -> Action.STAND.equals(playerTurnStatusMap.get(p)) || p.isBust()); if (!allPlayersDone) return;

int dealerValue = dealer.getHand().getPossibleValues().last(); boolean dealerBusts = dealer.isBust();

for (Player player : players) { if (player.isBust()) { player.loseBet(); } else { int playerValue = player.getHand().getPossibleValues().last(); if (dealerBusts || playerValue > dealerValue) { player.payout(); } else if (playerValue == dealerValue) { player.returnBet(); } else { player.loseBet(); } } } currentPhase = GamePhase.END; } } ```

Chuqur O'rganish — Qaror Logikasini Ajratish (Strategy Pattern)

Joriy dizaynda dilerin "17 gacha karta ol" qoidasi `dealerTurn()`'da qattiq kodlangan. Har qanday qoida o'zgarishi `BlackJackGame`'ni o'zgartirishni talab qiladi. Biz buni **Strategy Pattern** yordamida ajratamiz.

**1-qadam: Qaror qabul qilish interfeysini aniqlash**

```java public interface PlayerDecisionLogic { Action decideAction(Hand hand); }

public class RealPlayerDecisionLogic implements PlayerDecisionLogic { @Override public Action decideAction(Hand hand) { return hand.getPossibleValues().last() < 16 ? Action.HIT : Action.STAND; } }

public class DealerDecisionLogic implements PlayerDecisionLogic { @Override public Action decideAction(Hand hand) { return hand.getPossibleValues().last() < 17 ? Action.HIT : Action.STAND; } } ```

**2–3-qadam: O'yinchilarga Integratsiya**

`RealPlayer` `RealPlayerDecisionLogic` (16 dan past karta ol) ishlatadi. `DealerPlayer` `DealerDecisionLogic` (17 dan past karta ol) ishlatadi. Har bir o'yinchi `Player` interfeysidan `getDecisionLogic()` ko'rsatadi.

**4-qadam: BlackJackGame'ni Qayta Ishlash**

```java public class BlackJackGame { // Maydonlar aslidan o'zgarishsiz...

// Yangilangan: dilerni qaror logikasi orqali odatiy o'yinchi sifatida ko'rib chiqadi public Player getNextEligiblePlayer() { if (currentPlayer == null) { for (Player player : players) { if (!Action.STAND.equals(playerTurnStatusMap.get(player)) && !player.isBust()) { currentPlayer = player; return currentPlayer; } } if (!Action.STAND.equals(playerTurnStatusMap.get(dealer))) { currentPlayer = dealer; return dealer; } } else { int currentIndex = players.indexOf(currentPlayer); for (int i = currentIndex + 1; i < players.size(); i++) { Player player = players.get(i); if (!Action.STAND.equals(playerTurnStatusMap.get(player)) && !player.isBust()) { currentPlayer = player; return currentPlayer; } } if (currentPlayer != dealer && !Action.STAND.equals(playerTurnStatusMap.get(dealer))) { currentPlayer = dealer; return dealer; } } return null; }

public void playNextTurn() { Player nextPlayer = getNextEligiblePlayer(); if (nextPlayer != null) { performPlayerAction(nextPlayer); } }

public void performPlayerAction(Player player) { Action action = player.getDecisionLogic().decideAction(player.getHand()); if (action == Action.HIT) { hit(player); } else if (action == Action.STAND) { stand(player); } } // dealerTurn() olib tashlandi — diler endi DealerDecisionLogic orqali performPlayerAction() oqimi bilan boshqariladi } ```

`playNextTurn()` `performPlayerAction()` ni chaqiradi, bu har bir o'yinchining qaror logikasiga murojaat qiladi. `dealerTurn()` olib tashlandi — diler endi `performPlayerAction()` oqimi tomonidan bir xil tarzda boshqariladi.

**Strategy Pattern xaritalash:** - `PlayerDecisionLogic` — strategiya shartnomasi - `RealPlayerDecisionLogic` / `DealerDecisionLogic` — konkret xatti-harakatlar - `BlackJackGame` — qaror ichki detallarini bilmasdan strategiyalardan foydalanadi

> **Eslatma:** Strategy Pattern haqida ko'proq bilib olish uchun Avtoturargoh bobiga murojaat qiling.

Xulosa

Bu bobda biz mustahkam Blackjack o'yinini qurib, javobgarliklarni `Card`, `Deck`, `Hand`, `Player` va `BlackJackGame` bo'yicha taqsimlabdik. Har bir qismning aniq roli bor: `Card` asosiylarni saqlaydi, `Deck` aralashtiradi va tarqatadi, `Hand` summalarni kuzatadi va `BlackJackGame` jarayonni boshqaradi.

Shuningdek, qaror qabul qilishni `PlayerDecisionLogic` bilan ajratibdik, o'yinchilar va diler uchun strategiyalarni qayta yozmasdan almashtirish oson bo'lsin deb Strategy Pattern'ni qo'lladiik.

Bob 12

Yuk Qutisi Tizimini Loyihalash

~8 daq o'qish

Bu bobda biz UPS, FedEx yoki Amazon Locker'ga o'xshash Yuk Qutisi tizimini loyihalashimiz. U mijozlarga onlayn buyurtmalarini qulay va xavfsiz olish imkoniyatini taqdim etadi. Tizim qutisi mavjudligini boshqaradi, kelayotgan paketlarni mos qutilarga tayinlaydi va paketlarni olish jarayonini ta'minlaydi.

Overview of the shipping locker system
Shipping Locker System

Talablarni Aniqlash

> **Nomzod:** Tizim bir nechta quti o'lchamlarini qo'llab-quvvatlaydimi? > **Intervyuer:** Ha. Paketlar joy optimallashtirish maqsadida mos keladigan eng kichik mavjud qutiga tayinlanadi.

> **Nomzod:** Paket kelganda nima bo'ladi va mijoz uni qanday oladi? > **Intervyuer:** Tizim to'g'ri o'lchamdagi ochiq qutini topadi, paketni tayinlaydi va mijozga quti joylashuvi va noyob kirish kodi bilan bildirishnoma yuboradi.

> **Nomzod:** Qutidan foydalanish uchun vaqt chegarasi yoki to'lov bormi? > **Intervyuer:** Ha. Bepul davr mavjud (oldindan belgilangan kunlar), keyin quti o'lchamiga qarab kunlik to'lov. Maksimal davrdan keyin xodimlar qutini tozalaydi.

> **Nomzod:** Tizim to'lovlarni qayta ishlaydi? > **Intervyuer:** Yo'q — tashqi xizmat to'lovni qayta ishlashni boshqaradi.

**Talablar** - Barcha qutilami kuzatish va turli quti o'lchamlarini qo'llab-quvvatlash. - Paket o'lchamini eng kichik mavjud imkoniyatga moslashtirish orqali qutilari tayinlash. - Mijozlar noyob kirish kodi bilan qutini ochadilar. - Quti siyosatiga asoslanib saqlash xarajatlarini kuzatish (quti o'lchamiga qarab kunlik tarif, bepul davr, maksimal davr).

**Funksional bo'lmagan talablar:** - Ishlash samaradorligini pasaytirmasdan joy bo'yicha yuqori hajmdagi quti operatsiyalarini boshqarish. - Yuqori mavjudlik — qutilarga har doim kirish mumkin bo'lishi kerak.

Asosiy Ob'yektlarni Aniqlash

- **Locker (Quti):** Alohida quti birligini ifodalaydi. - **Site (Joy):** Turli o'lchamdagi bir nechta qutini o'z ichiga oluvchi quti ob'yekti, ularni samarali tayinlash uchun o'lcham bo'yicha tashkil etadi. - **ShippingPackage (Yuk Paketi):** Paket standartlarini belgilaydigan interfeys; `BasicShippingPackage` buyurtma ID, o'lchamlar va holatni kuzatuvchi konkret amalga oshirish hisoblanadi. - **Account (Hisob):** Mijozlar va ularning hisoblarini ifodalaydi, siyosat ma'lumotlarini (bepul davr, maksimal davr) va joriy balansni saqlaydi.

Sinflar Diagrammasini Loyihalash — Locker va LockerSize

**Locker (Quti)**

Fizik saqlash birligini ifodalaydi. Atributlar: `LockerSize size`, `ShippingPackage currentPackage`, `Date assignmentDate`, `String accessCode`. Metodlar: paket tayinlash, qutini bo'shatish, saqlash to'lovini hisoblash, mavjudligini tekshirish, kirish kodini tasdiqlash.

> **Dizayn tanlovi:** Modullilik uchun alohida qutining holati va xatti-harakatini inkapsuliyalaydigan mustaqil sub'yekt sifatida loyihalangan.

**LockerSize**

Oldindan belgilangan o'lchamli enum (SMALL, MEDIUM, LARGE), har biri `sizeName`, `dailyCharge` va fizik o'lchamlarga (`width`, `height`, `depth`) ega.

> **Dizayn tanlovi:** Satrlar yoki butun sonlar ustidan enum — type-safe, o'qilishi oson, to'g'ri o'lchamlar to'plamini ta'minlaydi.

UML diagram of Locker class with size, currentPackage, assignmentDate, and accessCode
Locker class diagram

Site, ShippingPackage, Account va LockerManager

**Site (Joy)**

`Map<LockerSize, Set<Locker>>` orqali o'lcham bo'yicha tashkil etilgan qutilari bo'lgan fizik manzilni modellashtiradi. Asosiy metodlar: `findAvailableLocker(LockerSize)` va `placePackage(ShippingPackage, Date)`.

**ShippingPackage (Yuk Paketi)**

Barcha paket turlari uchun interfeys. `BasicShippingPackage` uni o'lchamlar va holatni kuzatib amalga oshiradi. `ShippingStatus` enum PENDING, STORED, RETRIEVED ni belgilaydi.

> **Dizayn tanlovi:** Interfeys asosiy logikani o'zgartirmasdan turli paket turlari (mo'rt, tez buziladigan) uchun kengaytirilishga imkon beradi.

**Account / AccountLockerPolicy**

`Account` mijoz balansini saqlaydi va `AccountLockerPolicy`'ga (bepul davr kunlari + maksimal davr kunlari) havola qiladi.

> **Dizayn tanlovi:** Mijoz ma'lumotlarini siyosat ma'lumotlaridan ajratish qo'llab-quvvatlash imkoniyatini yaxshilaydi va shaxsiylashtirilgan hisob-kitob qoidalarini ta'minlaydi.

**NotificationInterface**

`sendNotification(message, account)` metodiga ega interfeys. Bildirishnoma logikasini moslashuvchan va tashqi saqlaydi.

> **Eng yaxshi amaliyot:** OOD intervyularida bildirishnomalar kabi tashqi tizimlar keraksiz murakkablikdan saqlanish uchun interfeys sifatida ifodalanadi.

**LockerManager**

Paket tayinlash va olishni muvofiqlashtiruvchi fasad. `Map<String, Account>` va `Map<String, Locker>` (kirish kodi → quti) ni saqlaydi.

> **Dizayn tanlovi:** Paket tayinlash, olish va bildirishnomalar uchun yagona boshqaruv nuqtasini taqdim etuvchi fasad.

UML diagram of Site class with lockers map and placement methods
Site class diagram
UML diagram of ShippingPackage interface, BasicShippingPackage, and ShippingStatus enum
ShippingPackage interface and ShippingStatus enum
UML diagram of Account class with lockerPolicy and usageCharges
Account class diagram
UML diagram of AccountLockerPolicy with freePeriodDays and maximumPeriodDays
AccountLockerPolicy class diagram
UML diagram of LockerManager facade with site, notification, accounts, and accessCodeMap
LockerManager class diagram
Full UML class diagram showing all shipping locker system components
Complete Class Diagram of Locker Service

Kod — Yuk Qutisi Xizmati

**Locker va LockerSize**

```java public class Locker { private final LockerSize size; private ShippingPackage currentPackage; private Date assignmentDate; private String accessCode;

public Locker(LockerSize size) { this.size = size; }

public void assignPackage(ShippingPackage pkg, Date date) { this.currentPackage = pkg; this.assignmentDate = date; this.accessCode = generateAccessCode(); }

public void releaseLocker() { this.currentPackage = null; this.assignmentDate = null; this.accessCode = null; }

public BigDecimal calculateStorageCharges() { if (currentPackage == null || assignmentDate == null) { return BigDecimal.ZERO; } AccountLockerPolicy policy = currentPackage.getUser().getLockerPolicy(); long totalDaysUsed = (new Date().getTime() - assignmentDate.getTime()) / (1000 * 60 * 60 * 24);

if (totalDaysUsed > policy.getMaximumPeriodDays()) { currentPackage.updateShippingStatus(ShippingStatus.EXPIRED); throw new MaximumStoragePeriodExceededException( "Paket ruxsat etilgan maksimal saqlash muddatidan oshib ketdi: " + policy.getMaximumPeriodDays() + " kun"); }

long chargeableDays = Math.max(0, totalDaysUsed - policy.getFreePeriodDays()); return size.dailyCharge.multiply(new BigDecimal(chargeableDays)); }

public boolean isAvailable() { return currentPackage == null; }

public boolean checkAccessCode(String code) { return this.accessCode != null && accessCode.equals(code); } } ```

```java public enum LockerSize { SMALL("Kichik", new BigDecimal("5.00"), new BigDecimal("10.00"), new BigDecimal("10.00"), new BigDecimal("10.00")), MEDIUM("O'rta", new BigDecimal("10.00"), new BigDecimal("20.00"), new BigDecimal("20.00"), new BigDecimal("20.00")), LARGE("Katta", new BigDecimal("15.00"), new BigDecimal("30.00"), new BigDecimal("30.00"), new BigDecimal("30.00"));

final String sizeName; final BigDecimal dailyCharge; final BigDecimal width; final BigDecimal height; final BigDecimal depth;

LockerSize(String sizeName, BigDecimal dailyCharge, BigDecimal width, BigDecimal height, BigDecimal depth) { this.sizeName = sizeName; this.dailyCharge = dailyCharge; this.width = width; this.height = height; this.depth = depth; } } ```

> **Amalga oshirish tanlovi:** `dailyCharge` va o'lchamlar uchun `BigDecimal` moliyaviy hisob-kitoblarda aniqlikni ta'minlaydi — `float`/`double` yaxlitlash xatolarini kiritadi.

**Site (Joy)**

```java public class Site { final Map<LockerSize, Set<Locker>> lockers = new HashMap<>();

public Site(Map<LockerSize, Integer> lockers) { for (Map.Entry<LockerSize, Integer> entry : lockers.entrySet()) { Set<Locker> lockerSet = new HashSet<>(); for (int i = 0; i < entry.getValue(); i++) { lockerSet.add(new Locker(entry.getKey())); } this.lockers.put(entry.getKey(), lockerSet); } }

public Locker findAvailableLocker(LockerSize size) { for (Locker locker : lockers.get(size)) { if (locker.isAvailable()) { return locker; } } return null; }

public Locker placePackage(ShippingPackage pkg, Date date) { LockerSize size = pkg.getLockerSize(); Locker locker = findAvailableLocker(size); if (locker != null) { locker.assignPackage(pkg, date); pkg.updateShippingStatus(ShippingStatus.IN_LOCKER); return locker; } throw new NoLockerAvailableException("" + size + " o'lchamidagi quti hozirda mavjud emas"); } } ```

> **Amalga oshirish tanlovy:** `placePackage()` bu operatsiyalar alohida bajarilganda yuzaga kelishi mumkin bo'lgan mos kelmaydigan holatlarning oldini oluvchi atomik topish-va-tayinlash xatti-harakatini taqdim etadi.

**BasicShippingPackage**

```java public class BasicShippingPackage implements ShippingPackage { private final String orderId; private final Account user; private final BigDecimal width; private final BigDecimal height; private final BigDecimal depth; private ShippingStatus status;

public BasicShippingPackage( String orderId, Account user, BigDecimal width, BigDecimal height, BigDecimal depth) { this.orderId = orderId; this.user = user; this.width = width; this.height = height; this.depth = depth; this.status = ShippingStatus.CREATED; }

@Override public ShippingStatus getStatus() { return status; }

@Override public void updateShippingStatus(ShippingStatus status) { this.status = status; }

// Ushbu paketning o'lchamlariga mos eng kichik quti o'lchamini qaytaradi @Override public LockerSize getLockerSize() { for (LockerSize size : LockerSize.values()) { if (size.getWidth().compareTo(width) >= 0 && size.getHeight().compareTo(height) >= 0 && size.getDepth().compareTo(depth) >= 0) { return size; } } throw new PackageIncompatibleException("Paket uchun mos quti o'lchami mavjud emas"); } } ```

**Account va AccountLockerPolicy**

```java public class Account { private final String accountId; private final String ownerName; private final AccountLockerPolicy lockerPolicy; private BigDecimal usageCharges = new BigDecimal("0.00");

public Account(String accountId, String ownerName, AccountLockerPolicy lockerPolicy) { this.accountId = accountId; this.ownerName = ownerName; this.lockerPolicy = lockerPolicy; }

public void addUsageCharge(BigDecimal amount) { usageCharges = usageCharges.add(amount); } }

public class AccountLockerPolicy { final int freePeriodDays; final int maximumPeriodDays;

public AccountLockerPolicy(int freePeriodDays, int maximumPeriodDays) { this.freePeriodDays = freePeriodDays; this.maximumPeriodDays = maximumPeriodDays; } } ```

**LockerManager**

```java public class LockerManager { private final Site site; private final NotificationInterface notificationService; private final Map<String, Account> accounts; private final Map<String, Locker> accessCodeMap = new HashMap<>();

public LockerManager( Site site, Map<String, Account> accounts, NotificationInterface notificationService) { this.site = site; this.accounts = accounts; this.notificationService = notificationService; }

public Locker assignPackage(ShippingPackage pkg, Date date) { Locker locker = site.placePackage(pkg, date); if (locker != null) { accessCodeMap.put(locker.getAccessCode(), locker); notificationService.sendNotification( "Paket qutiga tayinlandi" + locker.getAccessCode(), pkg.getUser()); } return locker; }

public Locker pickUpPackage(String accessCode) { Locker locker = accessCodeMap.get(accessCode); if (locker != null && locker.checkAccessCode(accessCode)) { try { BigDecimal charge = locker.calculateStorageCharges(); ShippingPackage pkg = locker.getPackage(); locker.releaseLocker(); pkg.getUser().addUsageCharge(charge); pkg.updateShippingStatus(ShippingStatus.RETRIEVED); return locker; } catch (MaximumStoragePeriodExceededException e) { locker.releaseLocker(); return locker; } } return null; } } ```

> **Eng yaxshi amaliyot:** `LockerManager`'ni yengil saqlang — past darajali operatsiyalarni (qutilami topish, paketlarni saqlash, siyosatlarni qo'llash) `Site` va `Locker`'ga topshiring.

Chuqur O'rganish — Quti Yaratish uchun Factory Pattern

Hozirda qutilар oldindan belgilangan o'lchamlarga asoslanib to'g'ridan-to'g'ri yaratiladi. Yangi quti turi qo'shish (masalan, XLARGE, harorat nazorat qilinadigan) kod bazasining bir nechta joylarini o'zgartirishni talab qiladi.

**Factory Pattern** quti yaratishni bitta sinfda markazlashtiradi:

```java class LockerFactory { public static Locker createLocker(LockerSize size) { return switch (size) { case SMALL -> new Locker(LockerSize.SMALL); case MEDIUM -> new Locker(LockerSize.MEDIUM); case LARGE -> new Locker(LockerSize.LARGE); case XLARGE -> new Locker(LockerSize.XLARGE); }; } } ```

**Afzalliklari:** - **Markazlashtirilgan yaratish:** Quti yaratishga o'zgarishlar `LockerFactory`'ga mahalliy. - **Kengaytirilish:** Asosiy biznes logikasiga tegmasdan yangi o'lcham/turlar qo'shiladi. - **SRP:** Quti yaratishni quti foydalanish logikasidan ajratadi.

UML diagram showing LockerFactory with createLocker factory method
LockerFactory class diagram

Chuqur O'rganish — Hodisalarni Boshqarish uchun Observer Pattern

Hozirda `LockerManager` to'g'ridan-to'g'ri `NotificationInterface.sendNotification()` chaqiradi, bu uni bildirishnoma tizimi bilan mahkam bog'laydi. **Observer Pattern**'dan foydalanish hodisalarni boshqarishni ajratadi:

```java class LockerManagerChange { private final List<LockerEventObserver> observers = new ArrayList<>();

public void addObserver(LockerEventObserver observer) { observers.add(observer); }

public void removeObserver(LockerEventObserver observer) { observers.remove(observer); }

private void notifyObservers(String message, Account account) { for (LockerEventObserver observer : observers) { observer.update(message, account); } }

public void assignPackage(ShippingPackage pkg) { Locker locker = assignLockerToPackage(pkg); if (locker != null) { notifyObservers("Paket qutiga tayinlandi", pkg.getUser()); } } }

public interface LockerEventObserver { void update(String message, Account account); }

class EmailNotification implements LockerEventObserver { public void update(String message, Account account) { // Hisob egasiga email yuborish } } ```

**Rollar:** - **Sub'yekt:** `LockerManagerChange` — kuzatuvchilar ro'yxatini saqlaydi, hodisalarni e'lon qiladi. - **Kuzatuvchi:** `LockerEventObserver` interfeysi — `update(message, account)` belgilaydi. - **Konkret Kuzatuvchilar:** `EmailNotification`, SMS, analitika — har biri mustaqil javob beradi.

> **Eslatma:** Observer Pattern haqida ko'proq ma'lumot olish uchun Lift Tizimi bobiga qarang.

UML diagram showing Observer pattern with LockerManagerChange, LockerEventObserver, and EmailNotification
Observer pattern for locker event handling

Xulosa

Bu bobda biz Yuk Qutisi Tizimini loyihaladik. Talablarni aniqladik, asosiy ob'yektlarni belgiladik, sinf diagrammasini ishlab chiqdik va asosiy komponentlarni amalga oshirdik.

Chuqur o'rganishda biz **Factory Pattern**'ning kengaytirilish uchun quti yaratishni qanday soddalashtirishi va **Observer Pattern**'ning moslashuvchan bildirishnomalar uchun hodisalarni boshqarishni qanday ajratishini o'rganik.

Qo'shimcha O'qish — Factory Dizayn Naqshi

**Factory Method Pattern** — sinf nusxalarini yaratish uchun interfeys taqdim etuvchi, lekin yaratilayotgan ob'yektlarning turini o'zgartirish imkonini kichik sinflarga beruvchi kreatsion dizayn naqshi.

**Muammo:** Elektron tijorat to'lov tizimi dastlab faqat kredit karta to'lovlarini qo'llab-quvvatlaydi. Raqamli hamyonlar yoki kriptovalyuta qo'shish har joyda mahkam bog'langan kodni o'zgartirishni talab qiladi.

**Yechim:** Factory metodi yaratishni inkapsuliyalaydi, mavjud kodni o'zgartirmasdan kichik sinflar orqali yangi to'lov turlarini qo'shish imkonini beradi.

**Qachon ishlatish kerak:** - Zarur ob'yektlarning muayyan turlari oldindan noma'lum bo'lganda. - Kutubxona foydalanuvchilariga mavjud kodni o'zgartirmasdan ichki komponentlarni kengaytirish imkonini bermoqchi bo'lganda. - Mavjud ob'yektlarni qayta foydalanish orqali resurs foydalanishni optimallashtirmoqchi bo'lganda.

UML diagram showing Factory pattern with PaymentFactory and concrete payment implementations
Factory design pattern — payment system example
Bob 13

ATM Tizimini Loyihalash

~7 daq o'qish

Bu bobda biz ATM tizimining ob'yektga yo'naltirilgan dizaynini ko'rib chiqamiz. ATMning asosiy maqsadi — foydalanuvchilar uchun bank operatsiyalarini avtomatlashtirish: balansni tekshirish, naqd pul yechib olish va mablag' o'tkazish. Ushbu dizayn ATM mashinasi, bank hisob raqamlari, apparat interfeyslari va tranzaksiya holatlari kabi asosiy komponentlarni modellashtiruvchi sinflar orqali bu operatsiyalarni muammosiz bajarishni ta'minlaydi.

Overview of the ATM system design
Automated Teller Machine (ATM)

Talablarni Aniqlash

> **Nomzod:** ATMda karta o'quvchi, klaviatura, ekran, naqd pul tarqatuvchi va depozit uyasi bo'lishi kerak. Bu asosiy komponentlarni qamrab oladimi? > **Suhbatdosh:** Yaxshi ro'yxat.

> **Nomzod:** ATM jarayoni: kartani kiritish → PIN kiritish → menyu (balansni tekshirish, yechib olish, depozit) → davom etish yoki chiqish → kartani qaytarish. Bu to'g'rimi? > **Suhbatdosh:** Jarayoningiz aniq.

> **Nomzod:** Autentifikatsiya uchun ATM karta + PINni tekshiradi, noto'g'ri bo'lsa xato ko'rsatadi. PIN urinishlarini cheklashimiz kerakmi? > **Suhbatdosh:** Ha — uch marta noto'g'ri PIN kiritilgandan so'ng karta bloklanadi. Bu doirada saqlab qoling.

> **Nomzod:** ATM kartaga ulangan Joriy va Jamg'arma hisoblarini qo'llab-quvvatlashi kerak. Foydalanuvchilar tranzaksiya uchun hisob tanlaydi. > **Suhbatdosh:** To'g'ri.

> **Nomzod:** Tranzaksiyalar uchun: Yechib olish (yetarli mablag'ni tekshiradi) va Depozit (balansni yangilaydi). O'tkazmalarni ham qo'shishimiz kerakmi? > **Suhbatdosh:** Faqat Yechib olish va Depozitga e'tibor qarating. O'tkazmalar doiradan tashqarida.

**Talablar** - Foydalanuvchilarni debet karta va PIN orqali autentifikatsiya qilish. - Foydalanuvchi uchun Joriy va Jamg'arma hisoblarini, hisob tanlashni qo'llab-quvvatlash. - Apparat: Karta O'quvchi, Klaviatura, Ekran, Naqd Pul Tarqatuvchi, Depozit Uyasi, ixtiyoriy Printer. - Validatsiyali Yechib olish va Depozit tranzaksiyalarini qo'llab-quvvatlash. - Yetarli mablag' yo'qligi, noto'g'ri PIN, apparat nosozligi uchun aniq xato xabarlari. Qayta noto'g'ri urinishlardan so'ng karta saqlab qolinadi.

Foydalanish Holati Diagrammasi

**Mijoz aktyori foydalanish holatlari:** Kartani kiritish, PIN kiritish, Tranzaksiya tanlash, Hisob tanlash, Naqd pul yechib olish, Mablag' depozit qilish, Kartani qaytarish.

**Tizim aktyori foydalanish holatlari:** Karta va PINni tekshirish, Naqd pul yechib olish, Mablag' depozit qilish, Kartani qaytarish.

UML use case diagram showing customer and system actor interactions with the ATM
Use Case Diagram of ATM

Asosiy Ob'yektlarni Aniqlash

- **Bank:** Hisoblarni saqlaydi va boshqaradi. - **Account:** Balans, hisob raqami, karta raqami, xeshlangan PIN va hisob turini (Joriy/Jamg'arma) boshqaradi. - **ATMMachine:** Foydalanuvchi bilan o'zaro ta'sirni boshqaruvchi va apparat bilan bog'lovchi asosiy koordinator (karta o'quvchi, klaviatura, ekran, naqd pul tarqatuvchi, depozit uyasi). - **Transaction:** Moliyaviy tranzaksiyalarni (yechib olish, depozit) validatsiya va bajarish bilan birga boshqaradi.

> **Dizayn Tanlovi:** Apparat kirishini `ATMMachine` ichida birlashtirish komponentlar bo'yicha izchil xatti-harakatni ta'minlaydi, kartani kiritishdan sessiya tugashigacha muammosiz foydalanuvchi oqimini ta'minlaydi.

Sinflar Diagrammasini Loyihalash

**Account**

Balans, hisob raqami, karta raqami, xeshlangan PIN va `AccountType` enumini (CHECKING/SAVING) o'z ichiga oladi. PIN tekshiruvi va balans yangilanishlarini amalga oshiradi.

> **Eslatma:** Haqiqiy bankdagidek tranzaksiya jurnalini saqlash o'rniga, soddalik va samarali doiralarni boshqarish uchun balansni bevosita yangilaymiz.

**Bank / BankInterface**

`Bank` sinfi `Account` ob'yektlarini saqlaydi va tezkor izlash uchun ularni kartalar bilan bog'laydi. `BankInterface` Bankni ATMdan ajratadi, bu mahalliy implementatsiyani ATM asosiy mantig'ini o'zgartirmasdan tarmoq API klienti bilan almashtirishga imkon beradi.

> **Muqobil:** Bankni ATMMachine ichiga integratsiya qilish hisob boshqaruvini ATM operatsiyalari bilan mahkam bog'laydi, bu modullilikni kamaytiradi.

**Transaction**

`Transaction` interfeysi barcha tranzaksiya turlari uchun shartnoma belgilaydi, `TransactionType` enumi (WITHDRAW, DEPOSIT) tomonidan qo'llab-quvvatlanadi. Konkret sinflar `WithdrawTransaction` va `DepositTransaction` o'z operatsiyalarini bajaradi.

> **Dizayn Tanlovi:** Tranzaksiyani alohida ob'yekt sifatida abstraksiyalash asosiy mantig'ni o'zgartirmasdan yangi turlarni (masalan, O'tkazma) kiritishni osonlashtiradi.

**ATMState**

Har bir ATM bosqichi uchun operatsiyalarni belgilovchi interfeys: kartani kiritish, PIN kiritish, tranzaksiya tanlash, miqdor kiritish, depozit yig'ish. Konkret holatlar: `IdleState`, `PinEntryState`, `TransactionSelectionState`, `WithdrawAmountEntryState`, `DepositCollectionState`.

**Apparat interfeyslari**

`CardProcessor`, `Keypad`, `Display`, `CashDispenser`, `DepositBox` — barchasi mock implementatsiyalar bilan testlashni ta'minlaydigan interfeyslar.

UML diagram of Account class with balance, PIN hash, and AccountType enum
Account class and AccountType enum
UML diagram of BankInterface and its Bank implementation
BankInterface and Bank class
UML diagram of Transaction interface with WithdrawTransaction and DepositTransaction
Transaction interface and concrete classes
UML diagram of ATMState hierarchy with IdleState, PinEntryState, and other states
ATMState interface and concrete classes
State machine diagram showing ATM transitions between Idle, PinEntry, TransactionSelection, WithdrawAmountEntry, and DepositCollection states
State transition diagram
UML diagram showing CardProcessor, Keypad, Display, CashDispenser, and DepositBox interfaces
Hardware component interfaces
UML diagram of ATMMachine facade class with hardware components and state management
ATMMachine class diagram
Full UML class diagram showing all ATM system components and their relationships
Complete Class Diagram of ATM System

Kod — ATM Tizimi

**Account va AccountType**

```java public class Account { private BigDecimal balance; private final String accountNumber; private final String cardNumber; private final byte[] cardPinHash; private final AccountType accountType;

public Account(final String accountNumber, final AccountType type, final String cardNumber, final String pin) { this.accountNumber = accountNumber; this.accountType = type; this.cardNumber = cardNumber; this.cardPinHash = calculateMd5(pin); // PIN is hashed for security this.balance = BigDecimal.ZERO; }

public boolean validatePin(String pinNumber) { byte[] entryPinHash = calculateMd5(pinNumber); return Arrays.equals(cardPinHash, entryPinHash); }

public void updateBalanceWithTransaction(final BigDecimal balanceChange) { this.balance = this.balance.add(balanceChange); } }

public enum AccountType { CHECKING, SAVING } ```

> **Implementatsiya Tanlovi:** Balans uchun `BigDecimal` aniq moliyaviy hisoblashlarni ta'minlaydi. `updateBalanceWithTransaction` bitta metod orqali ham depozitlarni (musbat), ham yechib olishlarni (manfiy) boshqaradi.

**BankInterface va Bank**

```java public interface BankInterface { void addAccount(String accountNumber, AccountType type, String cardNumber, String pin); boolean validateCard(String cardNumber); boolean checkPin(String cardNumber, String pinNumber); Account getAccountByAccountNumber(String accountNumber); Account getAccountByCard(String cardNumber); boolean withdrawFunds(Account account, BigDecimal amount); }

public class Bank implements BankInterface { private final Map<String, Account> accounts = new HashMap<>(); private final Map<String, Account> accountByCard = new HashMap<>();

@Override public void addAccount(final String accountNumber, final AccountType type, final String cardNumber, final String pin) { final Account newAccount = new Account(accountNumber, type, cardNumber, pin); accounts.put(newAccount.getAccountNumber(), newAccount); accountByCard.put(newAccount.getCardNumber(), newAccount); }

@Override public boolean validateCard(final String cardNumber) { return getAccountByCard(cardNumber) != null; }

@Override public boolean checkPin(String cardNumber, String pinNumber) { Account account = getAccountByCard(cardNumber); if (account != null) { return account.validatePin(pinNumber); } return false; }

@Override public Account getAccountByAccountNumber(String accountNumber) { return accounts.get(accountNumber); }

@Override public Account getAccountByCard(String cardNumber) { return accountByCard.get(cardNumber); }

@Override public boolean withdrawFunds(Account account, BigDecimal amount) { if (account.getBalance().compareTo(amount) >= 0) { account.updateBalanceWithTransaction(amount.negate()); return true; } return false; } } ```

> **Implementatsiya Tanlovi:** Ikkita `HashMap` — `accounts` (hisob raqami → Account) va `accountByCard` (karta raqami → Account) — karta validatsiyasi va hisob izlash kabi real vaqt operatsiyalari uchun O(1) qidiruvni ta'minlaydi.

**Transaction, WithdrawTransaction, DepositTransaction**

```java public interface Transaction { TransactionType getType(); boolean validateTransaction(); void executeTransaction(); }

public class WithdrawTransaction implements Transaction { Account account; BigDecimal amount;

public WithdrawTransaction(Account account, BigDecimal amount) { if (!validateTransaction()) { throw new IllegalStateException( "Cannot complete withdrawal: Insufficient funds in account"); } this.account = account; this.amount = amount; }

@Override public TransactionType getType() { return TransactionType.WITHDRAW; }

@Override public boolean validateTransaction() { assert account != null; return account.getBalance().compareTo(amount) > 0; }

@Override public void executeTransaction() { account.updateBalanceWithTransaction(amount.negate()); } }

public class DepositTransaction implements Transaction { final Account account; final BigDecimal amount;

public DepositTransaction(Account account, BigDecimal amount) { this.account = account; this.amount = amount; }

@Override public TransactionType getType() { return TransactionType.DEPOSIT; }

@Override public boolean validateTransaction() { return true; // Deposits are always valid }

@Override public void executeTransaction() { account.updateBalanceWithTransaction(amount); } } ```

**ATMState (asosiy + IdleState + WithdrawAmountEntryState)**

```java public class ATMState { private static void renderDefaultAction(ATMMachine atmMachine) { atmMachine.getDisplay().showMessage("Invalid action, please try again."); }

public void processCardInsertion(ATMMachine atmMachine, String cardNumber) { renderDefaultAction(atmMachine); }

public void processCardEjection(ATMMachine atmMachine) { renderDefaultAction(atmMachine); }

public void processPinEntry(ATMMachine atmMachine, String pin) { renderDefaultAction(atmMachine); }

public void processWithdrawalRequest(ATMMachine atmMachine) { renderDefaultAction(atmMachine); }

public void processDepositRequest(ATMMachine atmMachine) { renderDefaultAction(atmMachine); }

public void processAmountEntry(ATMMachine atmMachine, BigDecimal amount) { renderDefaultAction(atmMachine); }

public void processDepositCollection(ATMMachine atmMachine, BigDecimal amount) { renderDefaultAction(atmMachine); } }

public class IdleState extends ATMState { @Override public void processCardInsertion(ATMMachine atmMachine, String cardNumber) { if (atmMachine.getBankInterface().validateCard(cardNumber)) { atmMachine.getDisplay().showMessage("Please enter your PIN"); atmMachine.transitionToState(new PinEntryState()); } else { atmMachine.getDisplay().showMessage("Invalid card. Please try again."); } } }

public class WithdrawAmountEntryState extends ATMState { @Override public void processCardEjection(ATMMachine atmMachine) { atmMachine.getDisplay().showMessage("Transaction cancelled, card ejected"); atmMachine.transitionToState(new IdleState()); }

@Override public void processAmountEntry(ATMMachine atmMachine, BigDecimal amount) { String cardNumber = atmMachine.getCardProcessor().getCardNumber(); Account account = atmMachine.getBankInterface().getAccountByCard(cardNumber); boolean isSuccess = atmMachine.getBankInterface().withdrawFunds(account, amount);

if (isSuccess) { atmMachine.getCashDispenser().dispenseCash(amount); atmMachine.getDisplay().showMessage("Please take your cash."); } else { atmMachine.getDisplay().showMessage("Insufficient funds, please try again."); } atmMachine.transitionToState(new TransactionSelectionState()); } } ```

> **Eslatma:** `PinEntryState`, `TransactionSelectionState` va `DepositCollectionState` qisqalik uchun o'tkazib yuborilgan — ularning to'liq kodi kitobning qo'shimcha materiallarida mavjud.

**ATMMachine**

```java public class ATMMachine { private ATMState state; private final CardProcessor cardProcessor; private final DepositBox depositBox; private final CashDispenser cashDispenser; private final Keypad keypad; private final Display display; private final Bank bank;

public ATMMachine(Bank bank, CardProcessor cardProcessor, DepositBox depositBox, CashDispenser cashDispenser, Keypad keypad, Display display) { this.bank = bank; this.cardProcessor = cardProcessor; this.depositBox = depositBox; this.cashDispenser = cashDispenser; this.keypad = keypad; this.display = display; this.state = new IdleState(); }

public void insertCard(String cardNumber) { state.processCardInsertion(this, cardNumber); }

public void ejectCard() { state.processCardEjection(this); }

public void enterPin(String pin) { state.processPinEntry(this, pin); }

public void withdrawRequest() { state.processWithdrawalRequest(this); }

public void depositRequest() { state.processDepositRequest(this); }

public void enterAmount(BigDecimal amount) { state.processAmountEntry(this, amount); }

public void collectDeposit(BigDecimal amount) { state.processDepositCollection(this, amount); }

public void transitionToState(ATMState nextState) { this.state = nextState; }

public ATMState getCurrentState() { return state; }

// Getters for hardware components public Display getDisplay() { return display; } public CashDispenser getCashDispenser() { return cashDispenser; } public BankInterface getBankInterface() { return bank; } public CardProcessor getCardProcessor() { return cardProcessor; } public Keypad getKeypad() { return keypad; } public DepositBox getDepositBox() { return depositBox; } } ```

Xulosa

Bu bobda biz ATM tizimini tuzilgan muloqot orqali talablarni yig'ish, asosiy ob'yektlarni aniqlash, sinflar tuzilmasini loyihalash va holat mashinasi hamda apparat o'zaro ta'sirini o'z ichiga olgan muhim komponentlarni implementatsiya qilish yo'li bilan loyihaladik.

Tizimning ta'mirlanuvchanligi mas'uliyatlarning aniq taqsimlanishi bilan ta'minlanadi: - `Account` va `Bank` hisob ma'lumotlari va bank operatsiyalarini boshqaradi - `Transaction` moliyaviy operatsiyalarni boshqaradi - `ATMState` va holat sinflari foydalanuvchi oqimining bosqichlarini boshqaradi - Apparat interfeyslari (`Keypad`, `CardProcessor` va boshqalar) foydalanuvchi o'zaro ta'sirini boshqaradi - `ATMMachine` facade sifatida hammasini muvofiqlashtiradi

`ATMState` bilan **State Pattern** dan foydalanish va apparat o'zaro ta'sirini interfeyslarga ajratish modullilikni yaxshilaydi va yangi tranzaksiya turlari yoki apparat komponentlari kabi kelajakdagi kengaytmalarni ta'minlaydi.

Bob 14

Restoran Boshqaruv Tizimini Loyihalash

~9 daq o'qish

Bu bobda biz Restoran Boshqaruv Tizimining dizaynini ko'rib chiqamiz. Maqsad — menyular, bronlar va stollar kabi tizimning muhim komponentlarini ifodalovchi sinflar yaratish. Bron qilish, buyurtmalarni boshqarish va stollarni tayinlash kabi muhim funksiyalarni qo'llab-quvvatlovchi, kelajakdagi yaxshilanishlar uchun ham sodda, ham moslashuvchan tizimni ishlab chiqamiz.

Overview image of restaurant reservation system
Restaurant reservation

Talablarni Aniqlash

> **Nomzod:** Tizim bronlarni, menyuni, buyurtma kuzatuvini va to'lovlarni boshqaradi. Hozircha bronlar va buyurtma boshqaruviga e'tibor qarataman. > **Suhbatdosh:** Oqilona boshlang'ich nuqta.

> **Nomzod:** Mijozlar bron qilib, boshqara oladimi? > **Suhbatdosh:** Ha, mijozlar mavjudligiga qarab stol bron qila oladi.

> **Nomzod:** Tizim stol mavjudligini qanday aniqlaydi? > **Suhbatdosh:** U guruh hajmiga mos va so'ralgan vaqtda bo'sh stolni tekshiradi. Har bir bron aynan bir soat davom etadi.

> **Nomzod:** Mijozlar bronni bekor qila oladimi? > **Suhbatdosh:** Ha.

> **Nomzod:** Bron qilgan mehmonlar kelganda, ular avtomatik ravishda stolga joylashtirilsinmi? > **Suhbatdosh:** Ha — ular ismini aytadi, tizim bronni va tayinlangan stolni topadi.

> **Nomzod:** Saflarsiz keluvchi mehmonlar haqida-chi? > **Suhbatdosh:** Hozirgi mavjudlik va guruh hajmiga qarab saflarsiz keladiganlarga stol tayinlang.

> **Nomzod:** Buyurtmalar berilgandan keyin o'zgartirilishi mumkinmi? > **Suhbatdosh:** Ha — elementlarni olib tashlash yoki miqdorini sozlash mumkin.

> **Nomzod:** Hisobni bo'lish qoidalari? > **Suhbatdosh:** Hozircha faqat bitta umumiy hisob miqdori.

**Talablar**

*Bronlar:* Kelajakdagi vaqt uchun stol bron qilish; bir soatlik uyalar; bir-birini qoplovchi bronlarni tekshirish; stol tayinlash; mijozlar ism bilan keladi; bekor qilish qo'llab-quvvatlanadi.

*Saflarsiz o'tirish:* Mavjudlik va guruh hajmiga qarab tayinlash.

*Buyurtma boshqaruvi:* Buyurtma berilgandan keyin elementlarni o'zgartirish/olib tashlash; buyurtma jarayonini kuzatish.

*Hisoblash:* Kassada bitta umumiy hisob.

Asosiy Ob'yektlarni Aniqlash

- **Menu:** Buyurtma uchun mavjud elementlarni saqlaydi. - **MenuItem:** Nomi va narxi bo'lgan alohida menyu elementi. - **Layout:** Restoranining fizik joylashuvi, barcha stollarni samarali tayinlash uchun tashkil etadi. - **Table:** Sig'im, joriy bronlar va faol buyurtmalarga ega alohida stol. - **Reservation:** Guruh ismi, hajmi, bron vaqti va tayinlangan stolni saqlaydi. - **ReservationManager:** Bron yaratish, izlash va bekor qilishni nazorat qiladi. Mavjudlikni tekshiradi va stollarni tayinlash uchun Layout bilan ishlaydi. - **Restaurant:** Bronlar, stol tayinlash, buyurtmalar va hisoblash uchun markaziy interfeys ta'minlovchi Facade. Boshqa sinflarga topshiradi.

Sinflar Diagrammasini Loyihalash

**Menu**

Tezkor buyurtma izlash uchun map ichida `MenuItem` ob'yektlarini saqlaydi (nom kalit sifatida). Menyu ma'lumotlarini `Restaurant` va `Table`dan ajratadi.

**MenuItem**

Nom, tavsif, narx va kategoriyani (`MAIN`, `APPETIZER`, `DESSERT`) saqlaydi. O'zgarmas — mustaqil qurilish bloki sifatida loyihalangan.

**Table**

O'zgarmas atributlar: `tableId`, `capacity`. O'zgaruvchan holat: `reservations` (vaqt bo'yicha) va `orderedItems` (MenuItem bo'yicha). Metodlar: buyurtmalarni qo'shish/olib tashlash, hisobni hisoblash, mavjudlikni tekshirish.

**Layout**

Stollarni ID va sig'im bo'yicha tashkil etadi. Eng kichik mos mavjud stolni samarali tayinlash uchun `SortedMap<Integer, Set<Table>>` (sig'im bo'yicha saralangan) dan foydalanadi.

> **Dizayn Tanlovi:** Stol tashkilotini `Layout`da ajratish tayinlash samaradorligini oshiradi va uni menyu/buyurtma mantiq'idan ajratadi. Uni `Restaurant`ga integratsiya qilish facade rolini haddan tashqari yuklaydi.

**OrderItem**

`MenuItem` bilan bog'liq va `Status` enumini orqali holatni kuzatadi: `PENDING` → `SENT_TO_KITCHEN` → `DELIVERED` (yoki `CANCELED`).

**ReservationManager**

Stollarni topish uchun `Layout`ga ulanadigan va `Reservation` ob'yektlarini saqlaydigan markaziy koordinator.

**Restaurant**

`ReservationManager` (bronlar/saflarsiz keluvchilar), `Menu` (elementlar) va `Table` (buyurtmalar/hisoblash) ga topshiradigan Facade.

> **Dizayn Tanlovi:** `Restaurant` facade sifatida uni e'tiborlashtirilgan holda saqlaydi. Barcha mantig'ni ichki boshqaradigan markaziy kontroller murakkablikni oshiradi.

UML diagram of Menu class with menuItems HashMap
Menu class diagram
UML diagram of MenuItem class with name, description, price, category and Category enum
MenuItem class and Category enum
UML diagram of Table class with reservations and orderedItems maps
Table class diagram
UML diagram of Layout class with tablesById and tablesByCapacity maps
Layout class diagram
UML diagram of OrderItem class with item, status, and Status enum
OrderItem class and Status enum
UML diagram of ReservationManager with layout reference and reservations set
ReservationManager class diagram
UML diagram of Restaurant facade class
Restaurant class diagram
Full UML class diagram showing all restaurant management system components
Complete Class Diagram of Restaurant Management System

Kod — Restoran Boshqaruv Tizimi

**Menu**

```java public class Menu { private final Map<String, MenuItem> menuItems = new HashMap<>();

public void addItem(MenuItem item) { menuItems.put(item.getName(), item); }

public MenuItem getItem(String name) { return menuItems.get(name); }

public Map<String, MenuItem> getMenuItems() { return Collections.unmodifiableMap(menuItems); } } ```

> **Implementatsiya Tanlovi:** `List` dan farqli o'laroq chiziqli qidiruv talab qilmaydigan nom asosidagi O(1) izlash uchun `HashMap`.

**MenuItem**

```java public class MenuItem { private final String name; private final String description; private final BigDecimal price; // BigDecimal for precise financial calculations private final Category category;

public MenuItem(String name, String description, BigDecimal price, Category category) { this.name = name; this.description = description; this.price = price; this.category = category; }

public enum Category { MAIN, APPETIZER, DESSERT } // getter methods are omitted for brevity } ```

**Table**

```java public class Table { private final int tableId; private final int capacity; private final Map<LocalDateTime, Reservation> reservations = new HashMap<>(); private final Map<MenuItem, List<OrderItem>> orderedItems = new HashMap<>();

public Table(int tableId, int capacity) { this.tableId = tableId; this.capacity = capacity; }

public BigDecimal calculateBillAmount() { return orderedItems.values().stream() .flatMap(List::stream) .map(OrderItem::getItem) .map(MenuItem::getPrice) .reduce(BigDecimal.ZERO, BigDecimal::add); }

public void addOrder(MenuItem item, int quantity) { for (int i = 0; i < quantity; i++) { addOrder(item); } }

public void addOrder(MenuItem item) { List<OrderItem> orderItems = orderedItems.get(item); if (orderItems == null) { orderItems = new ArrayList<>(); orderedItems.put(item, orderItems); } orderItems.add(new OrderItem(item)); }

public void removeOrder(MenuItem item) { List<OrderItem> orderItems = orderedItems.get(item); if (orderItems != null) { orderItems.remove(0); if (orderItems.isEmpty()) { orderedItems.remove(item); } } }

public boolean isAvailableAt(LocalDateTime reservationTime) { return !reservations.containsKey(reservationTime); }

public void addReservation(Reservation reservation) { reservations.put(reservation.getTime(), reservation); }

public void removeReservation(LocalDateTime reservationTime) { reservations.remove(reservationTime); } } ```

**Layout**

```java public class Layout { private final Map<Integer, Table> tablesById = new HashMap<>(); // SortedMap groups tables by capacity, smallest to largest private final SortedMap<Integer, Set<Table>> tablesByCapacity = new TreeMap<>();

public Layout(List<Integer> tableCapacities) { for (int i = 0; i < tableCapacities.size(); i++) { int capacity = tableCapacities.get(i); Table table = new Table(i, capacity); tablesById.put(i, table); tablesByCapacity.computeIfAbsent(capacity, k -> new HashSet<>()).add(table); } }

// Finds the smallest available table that fits the party at the given time public Table findAvailableTable(int partySize, LocalDateTime reservationTime) { for (Set<Table> tables : tablesByCapacity.tailMap(partySize).values()) { for (Table table : tables) { if (table.isAvailableAt(reservationTime)) { return table; } } } return null; } } ```

> **Implementatsiya Tanlovi:** `tablesByCapacity` uchun `SortedMap` (TreeMap) saralangan kalit kirishini va `tailMap(partySize)` orqali samarali diapazon qidiruvlarini ta'minlaydi. Oddiy `Map` eng kichik mos stolni topish uchun qo'shimcha mantiq talab qiladi.

**OrderItem**

```java public class OrderItem { private final MenuItem item; private Status status = Status.PENDING;

public OrderItem(MenuItem item) { this.item = item; }

public void sendToKitchen() { if (status == Status.PENDING) status = Status.SENT_TO_KITCHEN; }

public void deliverToCustomer() { if (status == Status.SENT_TO_KITCHEN) status = Status.DELIVERED; }

public void cancel() { if (status == Status.PENDING || status == Status.SENT_TO_KITCHEN) { status = Status.CANCELED; } }

public enum Status { PENDING, SENT_TO_KITCHEN, DELIVERED, CANCELED } } ```

**ReservationManager va Reservation**

```java public class ReservationManager { private final Layout layout; private final Set<Reservation> reservations = new HashSet<>();

public ReservationManager(Layout layout) { this.layout = layout; }

public LocalDateTime[] findAvailableTimeSlots( LocalDateTime rangeStart, LocalDateTime rangeEnd, int partySize) { LocalDateTime current = rangeStart; List<LocalDateTime> possibleReservations = new ArrayList<>(); while (!current.isAfter(rangeEnd)) { Table availableTable = layout.findAvailableTable(partySize, current); if (availableTable != null) { possibleReservations.add(current); } current = current.plusHours(1); } return possibleReservations.toArray(new LocalDateTime[0]); }

public Reservation createReservation( String partyName, int partySize, LocalDateTime desiredTime) { desiredTime = desiredTime.truncatedTo(ChronoUnit.HOURS); Table table = layout.findAvailableTable(partySize, desiredTime); Reservation reservation = new Reservation(partyName, partySize, desiredTime, table); table.addReservation(reservation); reservations.add(reservation); return reservation; }

public void removeReservation( String partyName, int partySize, LocalDateTime reservationTime) { for (Reservation reservation : new HashSet<>(reservations)) { if (reservation.getTime().equals(reservationTime) && reservation.getPartySize() == partySize && reservation.getPartyName().equals(partyName)) { reservation.getAssignedTable().removeReservation(reservationTime); reservations.remove(reservation); return; } } } }

public class Reservation { private final String partyName; private final int partySize; private final LocalDateTime time; private final Table assignedTable;

public Reservation(String partyName, int partySize, LocalDateTime time, Table assignedTable) { this.partyName = partyName; this.partySize = partySize; this.time = time; this.assignedTable = assignedTable; } // getter methods are omitted for brevity } ```

> **Implementatsiya Tanlovi:** `Set<Reservation>` takror bronlarni oldini oladi. `List` oddiyroq iteratsiyaga imkon beradi, lekin takrorlanish xavfini tug'diradi. Vaqt asosidagi kalitlar bilan `Map` izlashni tezlashtirishi mumkin, lekin o'chirishni murakkablashtiradi.

**Restaurant**

```java public class Restaurant { private final String name; private final Menu menu; private final Layout layout; private final ReservationManager reservationManager;

public Restaurant(String name, Menu menu, Layout layout) { this.name = name; this.menu = menu; this.layout = layout; this.reservationManager = new ReservationManager(layout); }

public LocalDateTime[] findAvailableTimeSlots( LocalDateTime rangeStart, LocalDateTime rangeEnd, int partySize) { return reservationManager.findAvailableTimeSlots(rangeStart, rangeEnd, partySize); }

public Reservation createScheduledReservation( String partyName, int partySize, LocalDateTime time) { return reservationManager.createReservation(partyName, partySize, time); }

public void removeReservation(String partyName, int partySize, LocalDateTime reservationTime) { reservationManager.removeReservation(partyName, partySize, reservationTime); }

public Reservation createWalkInReservation(String partyName, int partySize) { return reservationManager.createReservation(partyName, partySize, LocalDateTime.now()); }

public void orderItem(Table table, MenuItem item) { table.addOrder(item); }

public void cancelItem(Table table, MenuItem item) { table.removeOrder(item); }

public BigDecimal calculateTableBill(Table table) { return table.calculateBillAmount(); } } ```

Chuqur O'rganish — Buyurtma Navbatini Kuzatish (Command Pattern)

Joriy dizaynda `Table` bevosita `OrderItem` holatini boshqaradi. Bu markazlashmagan tuzilma qoʻzg'aluvchan soatlarda barcha stollar bo'yicha buyurtma jarayonining yaxlit ko'rinishini ta'minlamaydi.

**Yechim: Command Pattern bilan markazlashtirilgan OrderManager**

```java public interface OrderCommand { void execute(); }

public class SendToKitchenCommand implements OrderCommand { private final OrderItem orderItem;

public SendToKitchenCommand(OrderItem orderItem) { this.orderItem = orderItem; }

@Override public void execute() { orderItem.sendToKitchen(); } }

public class DeliverCommand implements OrderCommand { private final OrderItem orderItem;

public DeliverCommand(OrderItem orderItem) { this.orderItem = orderItem; }

@Override public void execute() { orderItem.deliverToCustomer(); } }

public class CancelCommand implements OrderCommand { private final OrderItem orderItem;

public CancelCommand(OrderItem orderItem) { this.orderItem = orderItem; }

@Override public void execute() { orderItem.cancel(); } }

public class OrderManager { private final List<OrderCommand> commandQueue = new ArrayList<>();

public void addCommand(OrderCommand command) { commandQueue.add(command); }

public void executeCommands() { for (OrderCommand command : commandQueue) { command.execute(); } commandQueue.clear(); } } ```

**OrderManager'ni Restaurant'ga integratsiya qilish:**

```java public class Restaurant { // ... fields unchanged ... private final OrderManager orderManager;

public Restaurant(String name, Menu menu, Layout layout) { // ... fields unchanged ... this.orderManager = new OrderManager(); }

public void orderItem(Table table, MenuItem item) { table.addOrder(item); List<OrderItem> orderItems = table.getOrderedItems().get(item); if (orderItems != null && !orderItems.isEmpty()) { OrderItem lastOrder = orderItems.get(orderItems.size() - 1); orderManager.addCommand(new SendToKitchenCommand(lastOrder)); orderManager.executeCommands(); } }

public void cancelItem(Table table, MenuItem item) { List<OrderItem> orderItems = table.getOrderedItems().get(item); if (orderItems != null && !orderItems.isEmpty()) { OrderItem lastOrder = orderItems.get(orderItems.size() - 1); orderManager.addCommand(new CancelCommand(lastOrder)); orderManager.executeCommands(); table.removeOrder(item); } }

public void deliverItem(Table table, MenuItem item) { List<OrderItem> orderItems = table.getOrderedItems().get(item); if (orderItems != null && !orderItems.isEmpty()) { OrderItem lastOrder = orderItems.get(orderItems.size() - 1); orderManager.addCommand(new DeliverCommand(lastOrder)); orderManager.executeCommands(); } } } ```

**Command Pattern rollari:** - **Command:** `OrderCommand` interfeysi + `SendToKitchenCommand` / `DeliverCommand` / `CancelCommand` - **Invoker:** `OrderManager` — buyruqlarni navbatga qo'yadi va bajarilishni ishga tushiradi - **Receiver:** `OrderItem` — haqiqiy holat o'zgarishlarini qayta ishlaydi

Afzalliklar: buyruqlarni guruhlash, kechiktirish, jurnal qilish yoki bekor qilish mumkin. Invoker buyruq nima qilishidan butunlay ajratilgan.

UML diagram showing Command pattern with OrderCommand interface, concrete commands, OrderManager invoker, and OrderItem receiver
Command pattern structure
UML diagram of OrderManager with commandQueue list and executeCommands method
OrderManager class with command queue

Xulosa

Bu bobda biz Restoran Boshqaruv Tizimini tuzilgan muloqot orqali talablarni yig'ish, asosiy ob'yektlarni aniqlash, sinflar tuzilmasini loyihalash va muhim komponentlarni implementatsiya qilish yo'li bilan loyihaladik.

Asosiy xulosalar: - **Modullilik + SRP:** `Menu`, `ReservationManager`, `Layout` va `Table` har biri alohida mas'uliyatni boshqaradi. - **Facade pattern:** `Restaurant` tizim operatsiyalarini birlashtiradi, ixtisoslashgan sinflarga topshiradi. - **O'zgarmaslik:** `MenuItem` ob'yektlari izchillik uchun o'zgarmasdir. - **Command Pattern (chuqur o'rganish):** `OrderManager` buyurtma harakatlarini markazlashtiradi, `Table` bilan bevosita bog'liqliksiz guruhlash, jurnal qilish va bekor qilishga imkon beradi.