Bugun Prototype patterniga to'xtalamiz. O'zbekchasiga Prototip yoki Namuna,asl nusxa ma'nolarini beradi.
Prototype - bu hosil qiluvchi design pattern bo‘lib, obyektlarni ularning ichki ishlash tafsilotlariga kirmasdan nusxalash imkonini beradi.
Oddiy qilib aytganda:
Tayyor namunani olib, undan yangi obyekt yasaymiz.
🚩 Muammo
Tasavvur qiling, sizda bir obyekt bor va undan nusxa olish kerak. Buni qanday qilasiz?
Oddiy yo‘l shunday ko‘rinadi:
Xuddi shu klassdan yangi bo‘sh obyekt yaratasiz.
Eski obyektning barcha maydonlarini birma-bir yangi obyektga ko‘chirasiz.
Ba’zan obyekt yaratish oson bo‘lmaydi. Unda ko‘p maydonlar bo‘lishi mumkin:
User user = new User();
user.setName("Ali");
user.setRole("ADMIN");
user.setStatus("ACTIVE");
user.setPermission("FULL_ACCESS");Agar bunday obyektlar ko‘p bo‘lsa, har safar ularni noldan yaratish noqulay bo‘ladi.
Yana bir muammo: Har doim ham obyektni bunday nusxalab bo‘lmaydi ya'ni obyekt ichidagi ba’zi maydonlar private bo‘lishi mumkin. Tashqi kod ularni bevosita ko‘chira olmaydi.
Yana bir muammo: nusxalash kodi aniq klasslarga bog‘lanib qoladi. Obyektning barcha maydonlarini ko‘chirish uchun uning klassini bilishingiz kerak bo‘ladi. Natijada siz obyektni faqat umumiy interfeys orqali bilsangiz, lekin aniq klassini bilmasangiz, uni nusxalay olmaysiz.
💡 Yechim
Prototype pattern nusxa yaratish vazifasini obyektning o‘ziga topshiradi.
Buning uchun barcha nusxalanadigan obyektlar uchun umumiy interfeys yaratiladi. Odatda bu interfeysda clone() metodi ishlatiladi:
clone()public interface Prototype {
Prototype clone();
}Har bir klass shu metodni yozadi va o‘zidan yangi nusxa qaytaradi.
Har bir klass o‘zining clone() metodida o‘zidan yangi nusxa yaratadi va maydonlarini ko‘chiradi.
Bu usul orqali hatto private maydonlarni ham nusxalash mumkin, chunki ko‘p dasturlash tillarida klass o‘zining boshqa obyektidagi private maydonlarga kira oladi.
Nusxa olinayotgan obyekt prototype deb ataladi.
Oddiy Javada misol
public class User implements Prototype {
private String name;
private String role;
public User(String name, String role) {
this.name = name;
this.role = role;
}
public User(User source) {
this.name = source.name;
this.role = source.role;
}
@Override
public User clone() {
return new User(this);
}
}Qo'llanilishi:
User admin = new User("Ali", "ADMIN");
User copyAdmin = admin.clone();Bu yerda copyAdmin — admin obyektining nusxasi.
Agar dasturda yuzlab maydonlarga ega, turli konfiguratsiyadagi obyektlar bo‘lsa, prototiplar ko‘plab subclass yaratish o‘rniga qulayroq yechim bo‘lishi mumkin.
Bunda dastur ishga tushganda kerakli prototip obyektlar oldindan tayyorlab qo‘yiladi. Keyin yangi obyekt kerak bo‘lsa, dastur shu tayyor prototipdan nusxa oladi.
🧬 Hayotiy misol
Ishlab chiqarishda asosiy mahsulotdan oldin prototiplar yaratiladi. Ular turli sinovlardan o‘tkaziladi. Lekin bunday prototip keyingi ishlab chiqarishda faol qatnashmaydi.
Pattern uchun yanada yaqinroq misol - hujayraning bo‘linishi.
Hujayra bo‘linganda undan ikkita bir xil hujayra hosil bo‘ladi. Asl hujayra prototip rolini bajaradi va yangi obyekt yaratishda faol ishtirok etadi.
🧩 Tuzilishi
Prototype pattern odatda quyidagi qismlardan iborat:
1. Prototip interfeysi
Bu interfeys klonlash amalini e’lon qiladi. Ko‘pincha unda faqat bitta metod bo‘ladi:
clone()2. Aniq prototip
Aniq klass o‘zini qanday klonlashni biladi.
Bu yerda shunchaki maydonlarni ko‘chirish bilan birga, murakkab ishlar ham bo‘lishi mumkin:
bog‘langan obyektlarni klonlash;
ichki obyektlarni to‘g‘ri nusxalash;
rekursiv bog‘liqliklarni hal qilish;
tashqi kod bilishi shart bo‘lmagan murakkab jarayonlarni yashirish.
3. Client
Client obyekt nusxasini aniq klass orqali emas, balki umumiy prototip interfeysi orqali yaratadi.
4. Prototiplar ombori
Ko‘p ishlatiladigan prototiplarni alohida joyda saqlash mumkin.
Masalan:
nom → prototipBu xuddi katalogga o‘xshaydi. Dastur kerakli nom yoki belgi bo‘yicha prototipni topadi va undan nusxa oladi.
Psevdokod g‘oyasi
Masalan, geometrik shakllar bor:
aylana;
to‘rtburchak;
uchburchak.
Har bir shakl clone() metodiga ega. Client shaklning aniq klassini bilmasa ham, undan nusxa ola oladi.
Ya’ni client uchun farqi yo‘q:
Shape copy = shape.clone();Bu yerda shape aylana bo‘lishi ham, to‘rtburchak bo‘lishi ham mumkin.
Qachon ishlatiladi?
1. Kod aniq klasslarga bog‘lanmasligi kerak bo‘lsa
Ba’zan siz obyektlar bilan faqat umumiy interfeys orqali ishlaysiz. Ularning aniq klassi sizga noma’lum bo‘ladi.
Bunday holatda Prototype yordam beradi. Client faqat clone() interfeysini biladi, aniq klasslarni bilishi shart emas.
2. Juda ko‘p subclasslar paydo bo‘lib ketganda
Agar siz har xil boshlang‘ich qiymatlarga ega obyektlar uchun alohida-alohida klasslar yaratishni boshlasangiz, klasslar soni juda ko‘payib ketadi.
Prototype pattern esa buni soddalashtiradi.
Subclass yaratish o‘rniga tayyor sozlangan obyektlar saqlanadi. Kerak bo‘lganda ulardan nusxa olinadi.
Natijada:
klasslar soni kamayadi;
kod soddalashadi;
obyekt yaratish tezlashadi.
Amalga oshirish bosqichlari
1. Prototip interfeysini yarating
Unda clone() metodi bo‘ladi.
public interface Prototype {
Prototype clone();
}Agar sizda allaqachon klasslar iyerarxiyasi bo‘lsa, clone() metodini shu klasslarning o‘zida e’lon qilish mumkin.
2. Nusxalovchi konstruktor qo‘shing
Klass ichida shu klass obyektini argument sifatida qabul qiladigan konstruktor yaratiladi.
Masalan:
public User(User source) {
this.name = source.name;
this.age = source.age;
}Bu konstruktor eski obyektning qiymatlarini yangi obyektga ko‘chiradi.
Agar klass meros olgan bo‘lsa, ota klass konstruktorini ham chaqirish kerak bo‘ladi.
3. clone() metodini yozing
Odatda clone() metodi juda sodda bo‘ladi:
@Override
public User clone() {
return new User(this);
}Muhim jihat: har bir klass o‘zining clone() metodini yozishi kerak. Aks holda nusxa ota klass obyektiga aylanishi mumkin.
4. Prototiplar omborini yarating
Kerak bo‘lsa, oldindan tayyorlangan obyektlarni bitta joyda saqlash mumkin.
Masalan:
Map<String, Prototype> prototypes = new HashMap<>();Keyin kerakli prototip olinadi va klonlanadi:
Prototype copy = prototypes.get("adminUser").clone();Afzalliklari
Obyektlarni aniq klasslariga bog‘lanmasdan klonlash mumkin.
Takroriy obyekt yaratish kodlari kamayadi.
Murakkab obyektlarni yaratish tezlashadi.
Ko‘plab subclasslar yaratish o‘rniga yaxshi alternativa bo‘ladi.
Oldindan sozlangan obyektlardan tez nusxa olish mumkin.
Kamchiliklari
Ichida boshqa obyektlarga link/reference saqlaydigan murakkab obyektlarni klonlash qiyin bo‘lishi mumkin.
Deep copy va shallow copy farqini to‘g‘ri tushunish kerak.Shallow copy — ichki obyektning o‘zi emas, faqat reference nusxalanadi. Deep copy — ichki obyektlar ham alohida nusxalanadi.
Bog‘langan obyektlar ko‘p bo‘lsa, klonlash logikasi murakkablashadi.
Boshqa patternlar bilan aloqasi
Ko‘p arxitekturalar avval Factory Method bilan boshlanadi, keyin murakkablik oshgani sari Abstract Factory, Prototype yoki Builder tomon rivojlanadi.
Abstract Factory ko‘pincha Factory Method orqali qilinadi, lekin ba’zan Prototype asosida ham qurilishi mumkin.
Agar Command obyektini tarixga qo‘shishdan oldin nusxalash kerak bo‘lsa, Prototype yordam beradi.
Composite va Decorator ishlatilgan murakkab obyekt strukturalarida Prototype foydali bo‘lishi mumkin. U butun obyekt tuzilmasini qayta yig‘ish o‘rniga klonlash imkonini beradi.
Prototype merosga kamroq tayanadi, lekin obyektni to‘g‘ri klonlash uchun murakkab boshlang‘ich sozlash talab qilishi mumkin.
Factory Method esa merosga tayanadi, lekin murakkab klonlash talab qilmaydi.
Ba’zan Memento pattern o‘rniga Prototype ishlatilishi mumkin, agar saqlanadigan obyekt oddiy bo‘lsa va tashqi resurslarga kuchli bog‘lanmagan bo‘lsa.
Abstract Factory, Builder va Prototype ba’zan Singleton orqali amalga oshirilishi mumkin.
Xulosa
Prototype pattern - bu tayyor obyektdan nusxa olib, yangi obyekt yaratish usuli.
Oddiy qilib aytganda:
Har safar noldan obyekt yasash o‘rniga, tayyor namunani olib, undan nusxa qilamiz.
Bu pattern ayniqsa obyekt yaratish qimmat, murakkab yoki ko‘p konfiguratsiyali bo‘lganda foydali.
Qachon ishlatamiz?
Prototype pattern quyidagi holatlarda foydali:
obyekt yaratish murakkab bo‘lsa;
obyekt ichida ko‘p sozlamalar bo‘lsa;
bir xil obyektlardan ko‘p nusxa kerak bo‘lsa;
kod aniq klasslarga qattiq bog‘lanib qolmasligi kerak bo‘lsa.