10-bo‘lim
Facade
Murakkab tizimga bitta oddiy kirish nuqtasi - va bu nima uchun soddalashtirish emas.
Ushbu bo‘lim mundarijasi
Facade - bir necha sinfdan iborat murakkab tizimga bitta oddiy kirish nuqtasi beradigan naqsh.
Bino fasadi kabi: ichkarida yuzlab xona bor, tashqarida esa bitta eshik.
Muammo: mijoz juda ko'p narsani biladi #
Buyurtmani rasmiylashtirish beshta quyi tizimni talab qiladi:
final class Ombor
{
/** @var array<string, int> */
private array $qoldiq = ['klaviatura' => 5, 'sichqoncha' => 0];
public function bormi(string $mahsulot, int $soni): bool
{
return ($this->qoldiq[$mahsulot] ?? 0) >= $soni;
}
public function band(string $mahsulot, int $soni): void
{
$this->qoldiq[$mahsulot] -= $soni;
echo " [ombor] {$mahsulot} x{$soni} band qilindi", PHP_EOL;
}
public function qoldiq(string $mahsulot): int
{
return $this->qoldiq[$mahsulot] ?? 0;
}
}
final class Toolov
{
public function yech(string $karta, int $summa): string
{
echo " [tolov] {$summa} som yechildi", PHP_EOL;
return 'trx_' . substr($karta, -4);
}
public function qaytar(string $trx): void
{
echo " [tolov] {$trx} qaytarildi", PHP_EOL;
}
}
final class Hisobfaktura
{
public function yarat(string $mijoz, int $summa, string $trx): string
{
echo " [hisob] hisob-faktura yaratildi", PHP_EOL;
return sprintf('HF-%s-%d', strtoupper(substr($mijoz, 0, 3)), $summa);
}
}
final class Xabarnoma
{
public function yubor(string $mijoz, string $matn): void
{
echo " [xabar] {$mijoz}: {$matn}", PHP_EOL;
}
}
final class Jurnal
{
public function yoz(string $xabar): void
{
echo " [jurnal] {$xabar}", PHP_EOL;
}
}
Mijoz kodi ularning hammasini to'g'ri tartibda chaqirishi kerak:
$ombor = new Ombor();
$tolov = new Toolov();
$hisob = new Hisobfaktura();
$xabar = new Xabarnoma();
$jurnal = new Jurnal();
// Mijoz kod - butun jarayonni o'zi boshqaradi
$mahsulot = 'klaviatura';
$soni = 2;
$narx = 250000;
$jurnal->yoz('buyurtma boshlandi');
if (!$ombor->bormi($mahsulot, $soni)) {
$jurnal->yoz('omborda yetarli emas');
} else {
$ombor->band($mahsulot, $soni);
$trx = $tolov->yech('8600123456781234', $narx * $soni);
$hf = $hisob->yarat('Husanboy', $narx * $soni, $trx);
$xabar->yubor('Husanboy', "Buyurtmangiz qabul qilindi: {$hf}");
$jurnal->yoz('buyurtma tugadi: ' . $hf);
}
[jurnal] buyurtma boshlandi
[ombor] klaviatura x2 band qilindi
[tolov] 500000 som yechildi
[hisob] hisob-faktura yaratildi
[xabar] Husanboy: Buyurtmangiz qabul qilindi: HF-HUS-500000
[jurnal] buyurtma tugadi: HF-HUS-500000
Buyurtma veb-saytdan, mobil ilovadan, admin paneldan va cron skriptidan kelishi mumkin. To'rtala joyda ham shu 15 qator yoziladi.
Muammolar:
| Muammo | Oqibati |
|---|---|
| Mijoz 5 ta sinfni biladi | Ularning biri o'zgarsa - 4 joy o'zgaradi |
| Tartib mijoz kodida | Kimdir to'lovni ombordan oldin qo'yadi |
| Xato ishlov berish takrorlanadi | Bir joyda unutiladi |
| To'lov qaytarish yo'q | Xato bo'lsa pul mijozda qolmaydi |
Oxirgisi eng jiddiy: yuqoridagi kodda hisob-faktura yaratishda xato chiqsa, pul allaqachon yechilgan bo'ladi va hech kim qaytarmaydi.
Yechim: bitta kirish nuqtasi #
final readonly class BuyurtmaNatijasi
{
public function __construct(
public bool $muvaffaqiyat,
public string $xabar,
public ?string $hisobfaktura = null,
) {}
}
final class BuyurtmaFasadi
{
public function __construct(
private Ombor $ombor,
private Toolov $tolov,
private Hisobfaktura $hisob,
private Xabarnoma $xabar,
private Jurnal $jurnal,
) {}
public function rasmiylashtir(
string $mijoz,
string $mahsulot,
int $soni,
int $narx,
string $karta,
): BuyurtmaNatijasi {
$this->jurnal->yoz("buyurtma: {$mijoz} / {$mahsulot} x{$soni}");
if (!$this->ombor->bormi($mahsulot, $soni)) {
$this->jurnal->yoz('omborda yetarli emas');
return new BuyurtmaNatijasi(false, 'Mahsulot omborda yoq');
}
$this->ombor->band($mahsulot, $soni);
$summa = $narx * $soni;
$trx = $this->tolov->yech($karta, $summa);
try {
$hf = $this->hisob->yarat($mijoz, $summa, $trx);
} catch (Throwable $x) {
// xato bo'lsa - pulni qaytaramiz
$this->tolov->qaytar($trx);
$this->jurnal->yoz('xato: ' . $x->getMessage());
return new BuyurtmaNatijasi(false, 'Texnik xato');
}
$this->xabar->yubor($mijoz, "Buyurtmangiz qabul qilindi: {$hf}");
$this->jurnal->yoz('tugadi: ' . $hf);
return new BuyurtmaNatijasi(true, 'Qabul qilindi', $hf);
}
}
function fasadYarat(): BuyurtmaFasadi
{
return new BuyurtmaFasadi(
new Ombor(), new Toolov(), new Hisobfaktura(),
new Xabarnoma(), new Jurnal(),
);
}
Mijoz kodi endi bitta qator:
$fasad = fasadYarat();
$natija = $fasad->rasmiylashtir(
mijoz: 'Husanboy',
mahsulot: 'klaviatura',
soni: 2,
narx: 250000,
karta: '8600123456781234',
);
echo '---', PHP_EOL;
echo 'muvaffaqiyat: ', $natija->muvaffaqiyat ? 'ha' : 'yoq', PHP_EOL;
echo 'hisob-faktura: ', $natija->hisobfaktura ?? '(yoq)', PHP_EOL;
[jurnal] buyurtma: Husanboy / klaviatura x2
[ombor] klaviatura x2 band qilindi
[tolov] 500000 som yechildi
[hisob] hisob-faktura yaratildi
[xabar] Husanboy: Buyurtmangiz qabul qilindi: HF-HUS-500000
[jurnal] tugadi: HF-HUS-500000
---
muvaffaqiyat: ha
hisob-faktura: HF-HUS-500000
Xato holati ham bir joyda hal qilingan:
$fasad = fasadYarat();
$natija = $fasad->rasmiylashtir(
mijoz: 'Malika',
mahsulot: 'sichqoncha', // omborda 0 dona
soni: 1,
narx: 120000,
karta: '8600123456781234',
);
echo '---', PHP_EOL;
echo 'muvaffaqiyat: ', $natija->muvaffaqiyat ? 'ha' : 'yoq', PHP_EOL;
echo 'xabar: ', $natija->xabar, PHP_EOL;
[jurnal] buyurtma: Malika / sichqoncha x1
[jurnal] omborda yetarli emas
---
muvaffaqiyat: yoq
xabar: Mahsulot omborda yoq
Fasad quyi tizimlarni yopmaydi #
$ombor = new Ombor();
$fasad = new BuyurtmaFasadi(
$ombor, new Toolov(), new Hisobfaktura(),
new Xabarnoma(), new Jurnal(),
);
// Fasad orqali
$fasad->rasmiylashtir('Nodira', 'klaviatura', 1, 250000, '8600111122223333');
// Kerak bo'lsa - to'g'ridan-to'g'ri
echo 'qoldiq: ', $ombor->qoldiq('klaviatura'), PHP_EOL;
$ombor->band('klaviatura', 1);
echo 'qoldiq: ', $ombor->qoldiq('klaviatura'), PHP_EOL;
[jurnal] buyurtma: Nodira / klaviatura x1
[ombor] klaviatura x1 band qilindi
[tolov] 250000 som yechildi
[hisob] hisob-faktura yaratildi
[xabar] Nodira: Buyurtmangiz qabul qilindi: HF-NOD-250000
[jurnal] tugadi: HF-NOD-250000
qoldiq: 4
[ombor] klaviatura x1 band qilindi
qoldiq: 3
Fasad quyi tizimlarga kirishni taqiqlamaydi. U shunchaki eng ko'p ishlatiladigan yo'lni oson qiladi.
| Holat | Nima ishlatiladi |
|---|---|
| Oddiy buyurtma | Fasad |
| Admin panelda qoldiqni tuzatish | To'g'ridan-to'g'ri Ombor |
| Hisobot uchun murakkab so'rov | To'g'ridan-to'g'ri quyi tizim |
Agar kirishni taqiqlash kerak bo'lsa - bu boshqa naqsh (masalan Proxy yoki modul chegarasi).
Fasad qachon noto'g'ri ishlatiladi #
// Bu fasad emas - bu foydasiz qatlam
final class OmborFasadi
{
public function __construct(private readonly Ombor $ombor) {}
public function bormi(string $m, int $n): bool
{
return $this->ombor->bormi($m, $n);
}
public function band(string $m, int $n): void
{
$this->ombor->band($m, $n);
}
}
$f = new OmborFasadi(new Ombor());
var_dump($f->bormi('klaviatura', 3));
bool(true)
Yuqoridagi sinf hech narsa soddalashtirmadi. U faqat
Ombor ning metodlarini takrorladi.
Fasadning belgisi - u bir nechta quyi tizimni birlashtiradi va ular orasidagi tartibni biladi.
Yana ikkita xato:
| Xato | Belgi |
|---|---|
| Xudo-fasad | Bitta sinfda 40 ta metod, hammasi har xil |
| Biznes mantiq fasadda | Narx hisoblash, chegirma qoidalari fasadda yozilgan |
Ikkinchisi ayniqsa xavfli. Fasad muvofiqlashtiradi, o'zi
qaror qabul qilmaydi. Chegirma qoidasi Chegirma sinfida
turishi kerak, fasadda emas.
Fasadni bo'lish #
Katta fasad o'sib ketsa - uni mavzu bo'yicha bo'ling:
// Bitta katta fasad o'rniga uchta aniq fasad
final class BuyurtmaBerish
{
public function __construct(private readonly Ombor $ombor) {}
public function tekshir(string $mahsulot, int $soni): string
{
return $this->ombor->bormi($mahsulot, $soni)
? 'mavjud' : 'yoq';
}
}
final class BuyurtmaBekorQilish
{
public function __construct(private readonly Toolov $tolov) {}
public function bekor(string $trx): string
{
$this->tolov->qaytar($trx);
return 'bekor qilindi';
}
}
echo (new BuyurtmaBerish(new Ombor()))->tekshir('klaviatura', 3), PHP_EOL;
echo (new BuyurtmaBekorQilish(new Toolov()))->bekor('trx_1234'), PHP_EOL;
mavjud
[tolov] trx_1234 qaytarildi
bekor qilindi
Har fasad bitta stsenariyni qoplaydi. Bu 2-bo'limdagi bir mas'uliyat tamoyilining fasadga tatbiqi.
Facade, Adapter va Mediator #
| Naqsh | Nechta obyekt | Interfeys | Maqsad |
|---|---|---|---|
| Adapter | Bitta | Mavjud interfeysga moslanadi | Ulash |
| Facade | Bir nechta | Yangi, soddaroq | Soddalashtirish |
| Mediator | Bir nechta | Yangi | Obyektlar bir-biri bilan gaplashmasin |
echo 'Adapter: begona -> bizniki (interfeys tarjima qilinadi)', PHP_EOL;
echo 'Facade: 5 sinf -> 1 metod (tartib fasadda)', PHP_EOL;
echo 'Mediator: A<->B<->C -> M (aloqa markazlashadi)', PHP_EOL;
Adapter: begona -> bizniki (interfeys tarjima qilinadi)
Facade: 5 sinf -> 1 metod (tartib fasadda)
Mediator: A<->B<->C -> M (aloqa markazlashadi)
Laravel da Cache::get(), DB::table() kabi chaqiruvlar
"facade" deb ataladi.
Lekin ular klassik Facade naqshi emas - ular Service Locator: statik metod konteynerdan obyektni topib beradi.
| GoF Facade | Laravel Facade | |
|---|---|---|
| Nechta sinfni birlashtiradi | Bir nechta | Odatda bitta |
| Chaqiruv | Obyekt metodi | Statik |
| Bog'liqlik ko'rinadimi | Ha, konstruktorda | Yo'q |
Ikkinchi ustun 6-bo'limdagi Singleton muammolarining aynan
o'zini keltirib chiqaradi. Laravel buni testda Cache::fake()
kabi vositalar bilan yumshatadi.
Nom bir xil bo'lgani bilan naqsh boshqa - buni bilib turing.
- Beshta quyi tizimni chaqiradigan mijoz kodini yozing.
- Uni to'rt joyda takrorlab ko'ring va nusxalar sonini sanang.
- Fasad yozing va mijoz kodini bir qatorga tushiring.
- Fasadga xato holatini va to'lovni qaytarishni qo'shing.
- Quyi tizimga to'g'ridan-to'g'ri murojaat qiling - ishladimi?
- Nima uchun fasad kirishni taqiqlamasligini tushuntiring.
- Bitta sinfni o'raydigan "fasad" yozing va nima foyda berganini ayting.
- Katta fasadni ikkita stsenariy fasadiga bo'ling.
- Facade, Adapter va Mediator farqini jadval qiling.
- Laravel Facade va GoF Facade farqini yozing.
Xulosa #
- Facade - murakkab tizimga bitta oddiy kirish nuqtasi.
- U quyi tizimlar orasidagi tartibni biladi va uni takrorlanishdan qutqaradi.
- Xato holatlari va tozalash (masalan to'lovni qaytarish) fasadda bir joyda hal qilinadi.
- Fasad murakkablikni yo'qotmaydi - uni bitta joyga to'playdi.
- Quyi tizimlarga to'g'ridan-to'g'ri murojaat ochiq qoladi - bu ataylab shunday.
- Bitta sinfni o'rash fasad emas - fasad bir nechta tizimni birlashtiradi.
- Fasadda biznes mantiq bo'lmasligi kerak - u faqat muvofiqlashtiradi.
- O'sib ketgan fasadni stsenariy bo'yicha bo'ling.
- Adapter interfeysni tarjima qiladi, Facade yangi va soddaroq interfeys yaratadi.
- Laravel dagi "facade" - boshqa naqsh (Service Locator), nomi shunchaki bir xil.
Keyingi bo'limda daraxtsimon tuzilmalarni bir xil ishlatishga imkon beradigan Composite ni ko'ramiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.