10-bo‘lim

Facade

Murakkab tizimga bitta oddiy kirish nuqtasi - va bu nima uchun soddalashtirish emas.

🕑 12 daqiqa o‘qish 📄 752 so‘z 👁 1 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Muammo: mijoz juda ko'p narsani biladi
  2. Yechim: bitta kirish nuqtasi
  3. Fasad quyi tizimlarni yopmaydi
  4. Fasad qachon noto'g'ri ishlatiladi
  5. Fasadni bo'lish
  6. Facade, Adapter va Mediator
  7. Xulosa

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:

PHP
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:

PHP
$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);
}
Natija
  [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
Bu kod har chaqiruv joyida takrorlanadi

Buyurtma veb-saytdan, mobil ilovadan, admin paneldan va cron skriptidan kelishi mumkin. To'rtala joyda ham shu 15 qator yoziladi.

Muammolar:

MuammoOqibati
Mijoz 5 ta sinfni biladiUlarning biri o'zgarsa - 4 joy o'zgaradi
Tartib mijoz kodidaKimdir to'lovni ombordan oldin qo'yadi
Xato ishlov berish takrorlanadiBir joyda unutiladi
To'lov qaytarish yo'qXato 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 #

PHP
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:

PHP
$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;
Natija
  [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:

PHP
$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;
Natija
  [jurnal] buyurtma: Malika / sichqoncha x1
  [jurnal] omborda yetarli emas
---
muvaffaqiyat: yoq
xabar: Mahsulot omborda yoq
Facade - beshta bog'lanish o'rniga bitta Fasadsiz Fasad bilan Kontroller Ombor Toolov Hisob Xabar Jurnal Har chaqiruv joyi 5 sinfni biladi Kontroller BuyurtmaFasadi Ombor Toolov Hisob Xabar Jurnal Chaqiruv joyi faqat fasadni biladi Murakkablik yo'qolmadi - u fasad ichiga ko'chdi. Foyda shundaki, endi u bitta joyda.
Fasad murakkablikni kamaytirmaydi - uni bir joyga to'playdi

Fasad quyi tizimlarni yopmaydi #

PHP
$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;
Natija
  [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
Bu ataylab shunday

Fasad quyi tizimlarga kirishni taqiqlamaydi. U shunchaki eng ko'p ishlatiladigan yo'lni oson qiladi.

HolatNima ishlatiladi
Oddiy buyurtmaFasad
Admin panelda qoldiqni tuzatishTo'g'ridan-to'g'ri Ombor
Hisobot uchun murakkab so'rovTo'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 #

PHP
// 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));
Natija
bool(true)
Bitta sinfni o'rash - fasad emas

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:

XatoBelgi
Xudo-fasadBitta sinfda 40 ta metod, hammasi har xil
Biznes mantiq fasaddaNarx 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:

PHP
// 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;
Natija
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 #

NaqshNechta obyektInterfeysMaqsad
AdapterBittaMavjud interfeysga moslanadiUlash
FacadeBir nechtaYangi, soddaroqSoddalashtirish
MediatorBir nechtaYangiObyektlar bir-biri bilan gaplashmasin
PHP
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;
Natija
Adapter:  begona -> bizniki   (interfeys tarjima qilinadi)
Facade:   5 sinf -> 1 metod   (tartib fasadda)
Mediator: A<->B<->C -> M      (aloqa markazlashadi)
Laravel dagi "Facade" boshqa narsa

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 FacadeLaravel Facade
Nechta sinfni birlashtiradiBir nechtaOdatda bitta
ChaqiruvObyekt metodiStatik
Bog'liqlik ko'rinadimiHa, konstruktordaYo'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.

Amaliy topshiriq
  1. Beshta quyi tizimni chaqiradigan mijoz kodini yozing.
  2. Uni to'rt joyda takrorlab ko'ring va nusxalar sonini sanang.
  3. Fasad yozing va mijoz kodini bir qatorga tushiring.
  4. Fasadga xato holatini va to'lovni qaytarishni qo'shing.
  5. Quyi tizimga to'g'ridan-to'g'ri murojaat qiling - ishladimi?
  6. Nima uchun fasad kirishni taqiqlamasligini tushuntiring.
  7. Bitta sinfni o'raydigan "fasad" yozing va nima foyda berganini ayting.
  8. Katta fasadni ikkita stsenariy fasadiga bo'ling.
  9. Facade, Adapter va Mediator farqini jadval qiling.
  10. 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.

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.