Oldingi maqoladan beri ancha vaqt o'tdi, vada qilganimdek keyingi eng kerakli patternlar seriyasi bilan tanishtirib boraman.
O'zbekchaga tarjima qilganda Fabrika Metodi bo'ladi. Biz uni asl terminda ishlatganimiz qulay va oson bo'ladi.
Factory Method - bu hosil qiluvchi design pattern bo‘lib, u obyektlarni yaratish uchun superclassda umumiy interfeys belgilaydi. Shu bilan birga, subclassga qaysi turdagi obyekt yaratilishini o‘zgartirish imkonini beradi.
Factory Method superclassda obyekt yaratish uchun umumiy usulni belgilaydi, lekin aniq qaysi obyekt yaratilishini subclasslar hal qiladi.
Boshqacha aytganda:
Asosiy class obyekt yaratish jarayonining umumiy qoidasini beradi, lekin yaratiladigan obyekt turini voris classlar tanlaydi.
U obyektlarni to‘g‘ridan-to‘g‘ri new orqali yaratish o‘rniga, ularni maxsus factory methodi orqali yaratishni taklif qiladi.
Factory Method qanday muammoni yechadi: Tasavvur qiling, siz yuk tashish tizimini ishlab chiqyapsiz.
Dastlab dastur faqat avtomobillar orqali yuk tashishni qo‘llab-quvvatlaydi. Shuning uchun kodning katta qismi Truck, ya’ni yuk mashinasi classi bilan ishlaydi.
Vaqt o‘tib, dastur mashhur bo‘lib ketadi va dengiz orqali yuk tashuvchi kompaniyalar ham tizimga qo‘shilmoqchi bo‘ladi. Endi dasturga Ship, ya’ni kema orqali tashish imkoniyatini qo‘shish kerak bo‘ladi.
Bir qarashda bu yaxshi yangilik. Lekin kod tomondan muammo paydo bo‘ladi.
Chunki mavjud kod Truck classiga qattiq bog‘langan. Endi Ship classini qo‘shish uchun kodning ko‘p joylarini o‘zgartirishga to‘g‘ri keladi. Keyinchalik yana boshqa transport turi, masalan poyezd yoki samolyot qo‘shilsa, yana shu ish takrorlanadi.
Natijada kod ichida ko‘plab if, else, switch operatorlari paydo bo‘ladi:
if (type.equals("truck")) {
return new Truck();
} else if (type.equals("ship")) {
return new Ship();
}Bunday kod vaqt o‘tishi bilan murakkablashadi, o‘qish qiyinlashadi va qo‘llab-quvvatlash og‘irlashadi.
Yechim
Factory Method patterni obyektlarni bevosita yaratmaslikni taklif qiladi.
Ya’ni:
new Truck()deb yozish o‘rniga, obyekt maxsus metod orqali olinadi:
createTransport()Bu metod fabrika metodi deyiladi.
Muhim jihat shundaki, obyekt baribir new orqali yaratiladi. Lekin bu ishni asosiy kod emas, fabrika metodi bajaradi.
Buning foydasi nimada?
Endi siz fabrika metodini voris classlarda qayta yozib, qaysi turdagi obyekt yaratilishini o‘zgartira olasiz.
Masalan:
RoadLogisticsclassiTruckyaratadi.SeaLogisticsclassiShipyaratadi.
Lekin asosiy kod uchun farqi yo‘q. U faqat umumiy Transport interfeysi bilan ishlaydi.
Oddiy misol
Bizda umumiy Transport interfeysi bor:
interface Transport {
void deliver();
}Yuk mashinasi shu interfeysni bajaradi:
class Truck implements Transport {
public void deliver() {
System.out.println("Yuk mashina orqali yetkazildi");
}
}Kema ham shu interfeysni bajaradi:
class Ship implements Transport {
public void deliver() {
System.out.println("Yuk kema orqali yetkazildi");
}
}Endi asosiy yaratuvchi class:
abstract class Logistics {
abstract Transport createTransport();
public void planDelivery() {
Transport transport = createTransport();
transport.deliver();
}
}Yo‘l logistika classi:
class RoadLogistics extends Logistics {
@Override
Transport createTransport() {
return new Truck();
}
}Dengiz logistika classi:
class SeaLogistics extends Logistics {
@Override
Transport createTransport() {
return new Ship();
}
}Ishlatilishi:
Logistics logistics = new RoadLogistics();
logistics.planDelivery();
Logistics seaLogistics = new SeaLogistics();
seaLogistics.planDelivery();Bu yerda asosiy kod Truck yoki Ship classlariga bog‘lanmagan. U faqat Transport interfeysi bilan ishlaydi.
Factory Method patternining asosiy g‘oyasi shundan kelib chiqadi:
Obyekt yaratish kodini asosiy biznes logikadan ajratish.
Ya’ni dastur transportni qanday yaratishni emas, transport bilan qanday ishlashni bilishi kerak.
Masalan, mijoz kodiga farqi yo‘q:
bu yuk mashinasimi;
kemami;
samolyotmi;
poyezdmi.
Unga faqat bitta narsa muhim:
transport.deliver();Ya’ni obyekt deliver() metodiga ega bo‘lsa bo‘ldi.
Factory Method tarkibi
Factory Method odatda 4 ta asosiy qismdan iborat bo‘ladi.
1. Product - mahsulot interfeysi
Bu umumiy interfeys bo‘lib, barcha yaratiladigan obyektlar shu interfeysga bo‘ysunadi.
Masalan:
interface Transport {
void deliver();
}2. Concrete Product - aniq mahsulotlar
Bular umumiy interfeysni amalga oshiradigan classlar.
Masalan:
class Truck implements Transport
class Ship implements TransportUlarning interfeysi bir xil, lekin ishlash usuli har xil.
3. Creator - yaratuvchi class
Bu class fabrika metodini e’lon qiladi.
abstract class Logistics {
abstract Transport createTransport();
}Ko‘pincha bu metod abstract bo‘ladi. Chunki har bir voris class uni o‘ziga moslab yozadi.
4. Concrete Creator - aniq yaratuvchi classlar
Bular fabrika metodini amalga oshiradi.
class RoadLogistics extends Logistics {
Transport createTransport() {
return new Truck();
}
}class SeaLogistics extends Logistics {
Transport createTransport() {
return new Ship();
}
}Factory Method qayerda ishlatiladi?
1. Qaysi obyekt kerakligi oldindan aniq bo‘lmaganda
Agar dastur keyinchalik turli xil obyektlar bilan ishlashi mumkin bo‘lsa, Factory Method foydali bo‘ladi.
Masalan, bugun faqat Truck bor. Ertaga Ship, keyin Plane qo‘shilishi mumkin.
Factory Method yordamida yangi transport turini qo‘shish uchun mavjud kodni buzish shart emas. Yangi class va yangi creator qo‘shiladi.
2. Framework yoki kutubxonani kengaytirish kerak bo‘lganda
Masalan, siz UI framework ishlatyapsiz. Unda standart to‘rtburchak tugmalar bor. Lekin sizga dumaloq tugmalar kerak.
Bunday holatda siz:
RoundButtonclassini yaratasiz;asosiy framework classidan voris olasiz;
createButton()metodini qayta yozasiz;endi framework standart tugma emas, sizning dumaloq tugmangizni yaratadi.
Bu usul frameworkni o‘zgartirmasdan, uni kengaytirish imkonini beradi.
Amalga oshirish bosqichlari
Factory Method patternini joriy qilish uchun odatda quyidagi bosqichlar bajariladi:
1. Umumiy interfeys yarating
Barcha yaratiladigan obyektlar bitta umumiy interfeysga ega bo‘lishi kerak.
Masalan:
interface Transport {
void deliver();
}2. Yaratuvchi classda fabrika metodi yarating
abstract Transport createTransport();Bu metod umumiy interfeys turini qaytarishi kerak.
3. new ishlatilgan joylarni toping
Kod ichida mahsulot obyektlari yaratilayotgan joylarni toping:
new Truck()Keyin ularni fabrika metodi bilan almashtiring:
createTransport()Afzalliklari:
Factory Method patternining asosiy afzalliklari:
1. Kod aniq classlarga qattiq bog‘lanib qolmaydi
Asosiy kod Truck, Ship, Plane kabi classlarni bilishi shart emas. U faqat umumiy interfeys bilan ishlaydi.
2. Obyekt yaratish logikasi bitta joyga yig‘iladi
Bu kodni tartibli qiladi. Obyekt qanday yaratilishi alohida joyda boshqariladi.
3. Yangi mahsulot qo‘shish osonlashadi
Yangi class qo‘shiladi va yangi creator yoziladi. Mavjud kodni ko‘p o‘zgartirish shart emas.
4. Open/Closed Principle’ga mos keladi
Ya’ni kod kengaytirishga ochiq, lekin mavjud kodni o‘zgartirishga yopiq bo‘ladi.
Bu SOLID prinsiplaridan biri.
Kamchiliklari
Factory Method ham har doim ideal yechim emas.
1. classlar soni ko‘payib ketishi mumkin
Har bir mahsulot uchun alohida creator kerak bo‘lsa, loyiha ichida classlar soni ortadi.
Masalan:
Truck -> RoadLogistics
Ship -> SeaLogistics
Plane -> AirLogistics
Train -> RailwayLogisticsKichik loyihalarda bu ortiqcha murakkablik bo‘lishi mumkin.
2. Oddiy holatlar uchun keragidan murakkab bo‘lishi mumkin
Agar dasturda faqat bitta obyekt turi bo‘lsa va yaqin kelajakda kengayish kutilmasa, Factory Method ishlatish shart emas.
Ba’zan oddiy new yetarli bo‘ladi.
Qachon ishlatish kerak?
Factory Method quyidagi holatlarda foydali:
obyekt turi runtime paytida tanlansa;
kod aniq classlarga bog‘lanib qolmasligi kerak bo‘lsa;
yangi mahsulot turlari keyinchalik qo‘shilishi kutilsa;
framework yoki library foydalanuvchiga kengaytirish imkonini berishi kerak bo‘lsa;
obyekt yaratish jarayonini markazlashtirish kerak bo‘lsa.
Qachon ishlatmaslik kerak?
Quyidagi holatlarda Factory Method ortiqcha bo‘lishi mumkin:
faqat bitta oddiy class yaratilsa;
kengaytirish ehtiyoji bo‘lmasa;
if/elsemuammosi yo‘q bo‘lsa;pattern ishlatish kodni soddalashtirmasa, aksincha murakkablashtirsa.
Boshqa patternlar bilan aloqasi
Factory Method boshqa yaratuvchi patternlar bilan bog‘liq.
Masalan:
Abstract Factory ko‘pincha Factory Method asosida quriladi.
Prototype obyektni nusxalash orqali yaratadi, Factory Method esa merosxo‘rlik orqali yaratadi.
Builder murakkab obyektlarni bosqichma-bosqich yaratishda ishlatiladi.
Template Method ichida Factory Method ishlatilishi mumkin.
Ko‘p arxitekturalar avval Factory Method bilan boshlanadi, keyinchalik loyiha murakkablashganda Abstract Factory, Builder yoki Prototype tomon rivojlanadi.
Qachon ishlatiladi?
Factory Method quyidagi holatlarda foydali:
Holat | Misol |
|---|---|
Obyekt turi keyin o‘zgarishi mumkin bo‘lsa | Truck, Ship, Plane |
Kod |
|
Yangi tur qo‘shish oson bo‘lishi kerak bo‘lsa | yangi transport qo‘shish |
Asosiy kod aniq classga bog‘lanmasligi kerak bo‘lsa | faqat |
Factory Method yordamida kod:
tartibli bo‘ladi;
kengaytirish osonlashadi;
asosiy kod aniq classlarga bog‘lanib qolmaydi;
yangi obyekt turini qo‘shish oson bo‘ladi.
Bu pattern har doim ham kerak emas.
Agar loyiha juda oddiy bo‘lsa va faqat bitta obyekt yaratilsa, Factory Method ortiqcha murakkablik bo‘lishi mumkin.
Masalan, faqat bitta Truck kerak bo‘lsa, oddiy new Truck() ham yetarli.
Xulosa qilsak:
Factory Method obyektni qanday yaratishni asosiy koddan yashiradi. Asosiy kod faqat umumiy interface bilan ishlaydi.