5.3 Foydali dizayn andozalari¶
β¬ οΈ Oldingi: 5.2 MVC β loyihani tartibga solish Β· π README Β· Keyingi: 5.4 Composer β tashqi kutubxonalar β‘οΈ
Dizayn andozasi (design pattern) β tez-tez uchraydigan muammolar uchun tayyor, sinovdan o'tgan yechim usuli. Ularni yoddan o'rganish shart emas β aksincha, ko'pini siz allaqachon (bilmasdan) ishlatdingiz! Bu bo'limda eng oddiy va foydalilarini, tanish misollar bilan ko'rsatamiz.
1) Bog'liqlikni uzatish (Dependency Injection)¶
Buni 5.2'da allaqachon ishlatdingiz! TalabaModelga $pdoni konstruktor orqali berdik:
<?php
class TalabaModel {
private $pdo;
public function __construct($pdo) { // bog'liqlikni tashqaridan olamiz
$this->pdo = $pdo;
}
}
$model = new TalabaModel($pdo); // kerakli narsani uzatamiz
Bunga Dependency Injection ("bog'liqlikni uzatish") deyiladi: class o'ziga kerakli narsani (bu yerda β bazaga ulanish) ichida yaratmaydi, balki tashqaridan oladi.
Nega yaxshi? Agar TalabaModel ichida o'zi new PDO(...) qilsa, uni sinash yoki o'zgartirish qiyin bo'lardi. Tashqaridan berganimizda β moslashuvchan: turli ulanishlar berishimiz mumkin (masalan, sinov uchun boshqasini). Oddiy qoida: class'ga kerakli narsalarni konstruktor orqali bering.
2) Almashtiriladigan xulq (Strategy)¶
Buni ham ko'rgansiz β 2.6'dagi interfeyslar! Esingizdami, Tolov interfeysi bo'lib, NaqdTolov va KartaTolov uni har xil amalga oshirardi, va ularni bir-biriga almashtirsa bo'lardi:
<?php
interface Tolov {
public function tasdiqla($summa);
}
class NaqdTolov implements Tolov { /* ... */ }
class KartaTolov implements Tolov { /* ... */ }
// To'lov turini istalgan vaqtda almashtirsa bo'ladi:
function buyurtmaTola(Tolov $tolov, $summa) {
$tolov->tasdiqla($summa);
}
Bu β Strategy andozasi: bir vazifani bajarishning turli usullarini (strategiyalarini) interfeys orqali almashtiriladigan qilish. Yangi usul qo'shsangiz (masalan, OnlaynTolov) β mavjud kodni o'zgartirmaysiz, faqat yangi class yozasiz.
3) Yaratishni bir joyga jamlash (Factory)¶
Ba'zan obyekt yaratish mantig'i murakkab yoki bir necha joyda kerak bo'ladi. Uni bitta funksiya/class'ga jamlaymiz β bu Factory ("fabrika"):
<?php
class TolovFactory {
public static function yarat($tur) {
return match($tur) {
'naqd' => new NaqdTolov(),
'karta' => new KartaTolov(),
default => throw new Exception("Noma'lum to'lov turi"),
};
}
}
// Endi obyekt yaratish bir joyda, oddiy:
$tolov = TolovFactory::yarat('karta');
Foydasi: obyekt yaratish mantig'i bir joyda. Yangi tur qo'shsangiz β faqat bu yerni yangilaysiz, butun loyiha bo'ylab emas.
Muhim ogohlantirish: andozani majburlamang¶
Andozalar β foydali, lekin ularni kerak bo'lmagan joyda ishlatmang. Oddiy ishga murakkab andoza qo'shish β kodni soddalashtirmaydi, balki chalkashtiradi. Andozani faqat u haqiqiy muammoni (masalan, almashtirib bo'ladigan xulq kerakligini) hal qilganda qo'llang. Boshlovchi sifatida: avval oddiy yozing; muammo paydo bo'lganda, mos andozani qo'llang. Tajriba bilan qaysi andoza qachon kerakligini his qilasiz.
Mashqlar¶
Oson
1. Dependency Injection: bir class'ga bog'liqlikni (masalan, $pdo yoki boshqa obyekt) konstruktor orqali bering.
2. 2.6'dagi Tolov interfeysi misolini Strategy andozasi sifatida qayta ko'rib chiqing β nega bu "almashtiriladigan xulq"?
3. Oddiy Factory yozing: tur nomiga qarab mos obyekt qaytaruvchi yarat($tur) metodi.
O'rta
4. Bildirishnoma Factory'si: 'email', 'sms' turlariga qarab mos class obyektini qaytarsin.
5. Strategy bilan: turli "chegirma" usullarini (OddiyChegirma, VIPChegirma) interfeys orqali almashtiriladigan qiling.
6. Dependency Injection foydasini ko'rsating: ichida new qiladigan class va konstruktor orqali oladigan class'ni yonma-yon yozing, farqini izohlang.
Qiyin
7. To'lov tizimini uchala andoza bilan birlashtiring: TolovFactory (yaratish) + Tolov interfeysi (Strategy, almashtirish) + Dependency Injection (kerakli obyektlarni uzatish). Qaysi andoza qaysi muammoni hal qilishini izohlang.
Yechim β 6 (DI farqi)
<?php
// β Bog'liqlikni ichida yaratish β moslashuvchan emas:
class HisobotYomon {
private $pdo;
public function __construct() {
// ulanish ma'lumoti shu yerga "qotirilgan" β o'zgartirish/sinash qiyin
$this->pdo = new PDO("mysql:host=localhost;dbname=maktab", "root", "");
}
}
// β
Bog'liqlikni tashqaridan olish (DI) β moslashuvchan:
class HisobotYaxshi {
private $pdo;
public function __construct($pdo) { // ulanish tashqaridan keladi
$this->pdo = $pdo;
}
}
// Yaxshi versiyada turli ulanish bera olamiz (masalan, sinov uchun boshqasini):
$pdo = new PDO("mysql:host=localhost;dbname=maktab", "root", "");
$hisobot = new HisobotYaxshi($pdo);
Yechim β 7 (uchala andozani birlashtirish)
<?php
// 1) Tolov β interfeys (Strategy: almashtiriladigan xulq)
interface Tolov {
public function tasdiqla($summa);
}
class NaqdTolov implements Tolov {
public function tasdiqla($summa) { return "Naqd: $summa so'm qabul qilindi"; }
}
class KartaTolov implements Tolov {
public function tasdiqla($summa) { return "Karta: $summa so'm yechildi"; }
}
// 2) TolovFactory β yaratishni bir joyga jamlaydi (Factory)
class TolovFactory {
public static function yarat($tur): Tolov {
return match($tur) {
'naqd' => new NaqdTolov(),
'karta' => new KartaTolov(),
default => throw new Exception("Noma'lum to'lov turi"),
};
}
}
// 3) Buyurtma β to'lovni TASHQARIDAN oladi (Dependency Injection)
class Buyurtma {
private $tolov;
public function __construct(Tolov $tolov) { // har qanday Tolov bo'lishi mumkin
$this->tolov = $tolov;
}
public function tola($summa) {
return $this->tolov->tasdiqla($summa);
}
}
// Ishlatish:
$tolov = TolovFactory::yarat('karta'); // Factory yaratadi
$buyurtma = new Buyurtma($tolov); // DI orqali beramiz
echo $buyurtma->tola(50000); // Karta: 50000 so'm yechildi
Har bir andoza o'z muammosini hal qiladi:
- Interfeys (Strategy): Buyurtma to'lov turini bilmaydi β har qanday Tolovni qabul qiladi. Yangi tur (OnlaynTolov) qo'shsangiz, Buyurtmani o'zgartirmaysiz.
- Factory: obyekt yaratish mantig'i bir joyda (TolovFactory). Yangi tur qo'shsangiz β faqat shu yerni yangilaysiz.
- Dependency Injection: Buyurtma to'lovni o'zi yaratmaydi, tashqaridan oladi β moslashuvchan va sinash oson.
Uchovi birga β kengaytiriladigan, toza tizim. Lekin esda tuting (5.3 boshidagi ogohlantirish): andozalarni faqat haqiqiy muammoni hal qilganda qo'llang.