WisarWisar
Dasturlash kitobi/9-QISM — Arxitektura33 daqiqa

9.2-bob: Design Patterns (dizayn naqshlari)

9-QISM — Arxitektura va ilg'or backend · 2-mavzu


1. Kirish va motivatsiya

SOLID 9.1-bob tamoyillarini bildik. Endi ularni amalga oshiradigan tayyor, sinovdan o'tgan yechimlarnidesign pattern'lar (dizayn naqshlari) — o'rganamiz. Design pattern — keng tarqalgan dasturlash muammolariga takrorlanadigan, isbotlangan yechimlar. Ular "g'ildirakni qaytadan ixtiro qilmaslik" imkonini beradi: ko'p dasturchilar duch kelgan muammoga, ko'p sinovdan o'tgan yechim. Bu — 1994'da "Gang of Four" (GoF) kitobida tizimlangan, hozir har dasturchining umumiy tili.

Pattern'larning eng katta foydasi — umumiy til (shared vocabulary). "Bu yerda Strategy ishlatamiz" deyilsa, jamoa darrov tushunadi (uzun tushuntirish kerak emas). Intervyu, code review, arxitektura muhokamasida — pattern nomlari asosiy til. Va eng muhimi: siz ularni allaqachon ishlatgansiz — NestJS DI (Singleton + Factory), middleware (Chain of Responsibility), to'lov turlari (Strategy), event'lar (Observer). Endi nomini, tuzilishini, qachon ishlatishni bilib olasiz.

Pattern'lar 3 turga bo'linadi: Creational (obyekt yaratish — Singleton, Factory, Builder), Structural (obyektlarni birlashtirish — Adapter, Decorator, Facade), Behavioral (obyektlar o'zaro aloqasi — Strategy, Observer, Chain of Responsibility). Bu bob: eng muhim, backend'da eng ko'p uchraydigan pattern'larni — TypeScript misollar bilan, qachon ishlatishni — chuqur ko'ramiz. Pattern — vosita, har joyga emas (over-engineering xavfi). Bu bob 9.1 (SOLID), 8 (NestJS) bilan bog'liq.

O'xshatish: design pattern'lar — oshpazning klassik retseptlari. Har oshpaz (dasturchi) noldan har taomni o'ylab topmaydi — sinovdan o'tgan retseptlar bor (palov, sho'rva pishirish usullari). "Strategy retsepti", "Factory retsepti" — ma'lum muammoga ma'lum yondashuv. Tajribali oshpaz retseptlarni biladi (qachon qaysi), lekin ko'r-ko'rona qo'llamaydi (har taomga zira solmaydi — kerakli joyda). Pattern'lar — dasturchining "retseptlar kitobi": muammoni ko'rganda, mos yechimni darrov tanlash mumkin.

Nega muhim?

  • Sinovdan o'tgan yechim — g'ildirakni qayta ixtiro qilmaslik.
  • Umumiy til — jamoa, intervyu, code review (pattern nomlari).
  • SOLID amalda — pattern'lar SOLID'ni qo'llaydi 9.1-bob.
  • NestJS asosi — DI, middleware, guard — pattern'lar.

2. Nazariya — chuqur tushuntirish

2.1. Design pattern nima va turlari

text
  Design pattern — keng muammoga takrorlanadigan, isbotlangan yechim (GoF 1994)

  3 TUR:
  CREATIONAL (yaratish):   Singleton, Factory, Builder, Prototype, Abstract Factory
  STRUCTURAL (tuzilma):    Adapter, Decorator, Facade, Proxy, Composite
  BEHAVIORAL (xulq):       Strategy, Observer, Chain of Responsibility, Command, State

   Pattern — vosita (har joyga emas — over-engineering xavfi)

Design pattern — umumiy muammoga isbotlangan yechim (GoF — 23 ta klassik). 3 tur: creational (obyekt yaratish), structural (birlashtirish), behavioral (o'zaro aloqa). Ular SOLID'ni 9.1-bob amalga oshiradi. Pattern — vosita (muammoga mos bo'lganda — har joyga emas). Bu bobda backend'da eng ko'p uchraydiganlar.

2.2. Singleton (yagona instance) — creational

typescript
// Singleton — butun ilovada BITTA instance (DB ulanish, config, logger)
class Database {
  private static instance: Database;
  private constructor() { /* ulanish */ }            // tashqaridan new mumkin emas

  static getInstance(): Database {
    if (!Database.instance) {
      Database.instance = new Database();             // bir marta
    }
    return Database.instance;
  }
}
const db1 = Database.getInstance();
const db2 = Database.getInstance();
console.log(db1 === db2);                             // true (bir xil instance)

Singleton — butun ilovada bitta instance (DB ulanish, config, logger). private constructor (tashqaridan new yo'q) + getInstance (bir marta yaratadi). NestJS provider'lar default singleton (8.1, 8.2: 2.10) — siz buni ishlatgansiz! Foyda: umumiy resurs (ulanish pool). Xavf: global holat (test qiyin — DI afzal).

2.3. Factory (obyekt yaratish) — creational

typescript
// Factory — obyekt yaratishni markazlashtirish (qaysi klass — factory hal qiladi)
interface Tolov {
  tolov(summa: number): Promise<void>;
}
class ClickTolov implements Tolov { async tolov(s: number) {} }
class PaymeTolov implements Tolov { async tolov(s: number) {} }

class TolovFactory {
  static yarat(tur: string): Tolov {                 // factory metod
    switch (tur) {
      case "click": return new ClickTolov();
      case "payme": return new PaymeTolov();
      default: throw new Error("Noma'lum to'lov turi");
    }
  }
}
const tolov = TolovFactory.yarat("click");           // qaysi klass — factory biladi

Factory — obyekt yaratishni markazlashtirish (klient qaysi konkret klass yaratilishini bilmaydi). Factory.yarat(tur) — turga qarab mos obyekt. Yaratish mantig'i bir joyda (DRY). OCP (9.1: 2.4) bilan — yangi tur qo'shish oson. NestJS: useFactory (8.2: 2.6) — Factory pattern! Foyda: yaratish ajratilgan, moslashuvchan.

2.4. Builder (murakkab obyekt) — creational

typescript
// Builder — murakkab obyektni bosqichma-bosqich qurish
class So'rovBuilder {
  private query: any = { where: {}, order: {}, limit: 10 };
  filter(maydon: string, qiymat: any) { this.query.where[maydon] = qiymat; return this; }
  sarala(maydon: string, yon: "ASC" | "DESC") { this.query.order[maydon] = yon; return this; }
  limit(n: number) { this.query.limit = n; return this; }
  build() { return this.query; }                      // yakuniy obyekt
}
const query = new So'rovBuilder()
  .filter("rol", "admin")
  .sarala("createdAt", "DESC")
  .limit(20)
  .build();                                            // zanjir (fluent)

Builder — murakkab obyektni bosqichma-bosqich qurish (ko'p ixtiyoriy parametr). Har metod this qaytaradi (zanjir — fluent API). build() — yakuniy. TypeORM QueryBuilder 6.13-bob, Mongoose query 8.13-bob — Builder pattern! Foyda: o'qiladigan (zanjir), moslashuvchan (kerakli qadamlar). Ko'p konstruktor parametri o'rniga.

2.5. Adapter (moslashtiruvchi) — structural

typescript
// Adapter — mos kelmaydigan interfeyslarni bog'lash
// Bizning interfeys
interface XabarYuboruvchi {
  yubor(kimga: string, matn: string): Promise<void>;
}
// Tashqi kutubxona (boshqa interfeys)
class TashqiSmsApi {
  sendSMS(phone: string, message: string, apiKey: string) { /* ... */ }
}
// Adapter — tashqi API'ni bizning interfeysga moslaydi
class SmsAdapter implements XabarYuboruvchi {
  constructor(private api: TashqiSmsApi, private apiKey: string) {}
  async yubor(kimga: string, matn: string) {
    this.api.sendSMS(kimga, matn, this.apiKey);       // moslashtirish
  }
}

Adapter — mos kelmaydigan interfeyslarni bog'laydi (tashqi kutubxona interfeysi bizning interfeys). SmsAdapter tashqi sendSMSni bizning yuborga moslaydi. Tashqi kutubxonani almashtirsa — faqat adapter o'zgaradi (qolgan kod tegmaydi — DIP — 9.1). To'lov provayder, SMS, eski API integratsiyasi uchun. Foyda: izolyatsiya.

2.6. Decorator (funksiya qo'shish) — structural

typescript
// Decorator — obyektga yangi xulq qo'shish (meros'siz, dinamik)
interface Kofe {
  narx(): number;
  tavsif(): string;
}
class OddiyKofe implements Kofe {
  narx() { return 10000; }
  tavsif() { return "Kofe"; }
}
// Decorator — Kofe'ni o'raydi va qo'shadi
class SutQoshimcha implements Kofe {
  constructor(private kofe: Kofe) {}
  narx() { return this.kofe.narx() + 3000; }          // qo'shimcha narx
  tavsif() { return this.kofe.tavsif() + " + sut"; }
}
class ShakarQoshimcha implements Kofe {
  constructor(private kofe: Kofe) {}
  narx() { return this.kofe.narx() + 1000; }
  tavsif() { return this.kofe.tavsif() + " + shakar"; }
}
let kofe: Kofe = new OddiyKofe();
kofe = new SutQoshimcha(kofe);                        // o'rash
kofe = new ShakarQoshimcha(kofe);                    // yana o'rash
console.log(kofe.tavsif(), kofe.narx());             // "Kofe + sut + shakar" 14000

Decorator — obyektga dinamik yangi xulq qo'shish (meros'siz — o'rab). Har decorator obyektni o'raydi, qo'shimcha mantiq beradi. Bu — TS @Decorator 7.6-bob tushunchasining asl manbai (NestJS dekoratorlar shu g'oyaga asoslangan). Interceptor 8.6-bob — Decorator ruhida. Foyda: moslashuvchan kengaytirish (kombinatsiya).

2.7. Facade (soddalashtiruvchi) — structural

typescript
// Facade — murakkab quyi tizimga oddiy interfeys
class Facade {
  constructor(
    private inventory: InventoryService,
    private payment: PaymentService,
    private shipping: ShippingService,
    private notification: NotificationService,
  ) {}
  // Murakkab jarayonni bitta oddiy metodga (klient detalni bilmaydi)
  async buyurtmaBer(dto: any): Promise<Order> {
    await this.inventory.tekshir(dto.items);
    await this.payment.tolov(dto.summa);
    const order = await this.shipping.yarat(dto);
    await this.notification.yubor(order);
    return order;
  }
}
// Klient: facade.buyurtmaBer(dto) — ichki 4 servisni bilmaydi

Facade — murakkab quyi tizimga oddiy interfeys (klient detal'ni bilmaydi). Ko'p servisni bitta oddiy metodga jamlaydi. NestJS service 8.1-bob — ko'pincha Facade (controller murakkablikni ko'rmaydi). Foyda: soddalik (klient bir metod chaqiradi), bog'liqlik kamayadi. Use-case 9.3-bob — Facade ruhida.

2.8. Proxy (vakil) — structural

typescript
// Proxy — obyektga kirishni nazorat (kesh, lazy, huquq)
interface Ma'lumot {
  ol(id: number): Promise<any>;
}
class HaqiqiyMa'lumot implements Ma'lumot {
  async ol(id: number) { /* og'ir DB so'rov */ return {}; }
}
// Proxy — kesh qo'shadi (kirishni nazorat)
class KeshProxy implements Ma'lumot {
  private kesh = new Map<number, any>();
  constructor(private haqiqiy: HaqiqiyMa'lumot) {}
  async ol(id: number) {
    if (this.kesh.has(id)) return this.kesh.get(id);  // keshdan (8.15)
    const data = await this.haqiqiy.ol(id);           // yo'q bo'lsa haqiqiy
    this.kesh.set(id, data);
    return data;
  }
}

Proxy — obyektga kirishni nazorat qiladi (o'zi bilan bir interfeys, lekin oraliqda mantiq). Turlari: kesh proxy 8.15-bob, lazy proxy (kerakda yaratish), himoya proxy (huquq tekshirish). KeshProxy haqiqiy obyekt o'rniga kesh qo'shadi. NestJS guard 8.6-bob — himoya proxy ruhida. Foyda: shaffof qo'shimcha (klient bilmaydi).

2.9. Strategy (almashtiriladigan algoritm) — behavioral

typescript
// Strategy — algoritmlar oilasini almashtiriladigan qilish (eng keng pattern)
interface SaralashStrategiyasi {
  sarala(data: number[]): number[];
}
class TezSaralash implements SaralashStrategiyasi {
  sarala(data: number[]) { return [...data].sort((a, b) => a - b); }
}
class TeskariSaralash implements SaralashStrategiyasi {
  sarala(data: number[]) { return [...data].sort((a, b) => b - a); }
}
class Saralovchi {
  constructor(private strategiya: SaralashStrategiyasi) {}   // strategiya (DIP)
  bajar(data: number[]) { return this.strategiya.sarala(data); }
}
const s = new Saralovchi(new TeskariSaralash());     // strategiyani tanlash

Strategy — algoritmlar oilasini almashtiriladigan qilish (eng keng ishlatiladigan). Har algoritm — alohida klass (bir interfeys), runtime'da tanlanadi. Bu — OCP (9.1: 2.4)ning amaliy ko'rinishi (yangi strategiya eski o'zgarmaydi). To'lov usullari, chegirma, saralash, validatsiya uchun. NestJS DI bilan tabiiy. Foyda: moslashuvchan, kengaytiriladigan.

2.10. Observer (kuzatuvchi) — behavioral

typescript
// Observer — obyekt o'zgarsa, kuzatuvchilarga xabar (event-driven asosi)
interface Kuzatuvchi {
  yangilan(data: any): void;
}
class Mavzu {
  private kuzatuvchilar: Kuzatuvchi[] = [];
  obuna(k: Kuzatuvchi) { this.kuzatuvchilar.push(k); }
  xabarBer(data: any) {                               // hammaga xabar
    this.kuzatuvchilar.forEach((k) => k.yangilan(data));
  }
}
// Buyurtma yaratilganda — email + SMS + statistika xabardor
class EmailKuzatuvchi implements Kuzatuvchi { yangilan(d: any) { /* email */ } }
class SmsKuzatuvchi implements Kuzatuvchi { yangilan(d: any) { /* sms */ } }

Observer — obyekt (subject) o'zgarganda, kuzatuvchilarga avtomatik xabar (publish-subscribe). Bu — Node.js EventEmitter 5.4-bob, NestJS event'lar (8.6: EventPattern — 8.16), WebSocket 8.18-bob, real-time 5.13-bob asosi! "One emits, others listen" — event-driven arxitektura 9.7-bob. Buyurtma email+SMS+statistika (bir-birini bilmaydi — loose coupling). Foyda: bo'shashgan bog'lanish.

2.11. Chain of Responsibility (zanjir) — behavioral

typescript
// Chain — so'rovni ishlovchilar zanjiri orqali o'tkazish (middleware asosi)
abstract class Ishlovchi {
  protected keyingi?: Ishlovchi;
  keyingiQoy(h: Ishlovchi) { this.keyingi = h; return h; }
  abstract ishla(sorov: any): any;
}
class AuthIshlovchi extends Ishlovchi {
  ishla(sorov: any) {
    if (!sorov.token) throw new Error("Auth kerak");
    return this.keyingi?.ishla(sorov);               // keyingiga
  }
}
class ValidatsiyaIshlovchi extends Ishlovchi {
  ishla(sorov: any) {
    if (!sorov.data) throw new Error("Data yo'q");
    return this.keyingi?.ishla(sorov);
  }
}
// auth  validatsiya  ... (zanjir)

Chain of Responsibility — so'rovni ishlovchilar zanjiri orqali o'tkazish (har biri ishlaydi yoki keyingiga uzatadi). Bu — middleware 5.6-bob, NestJS pipe/guard/interceptor 8.6-bob asosi! Har bosqich so'rovni ishlaydi (auth validatsiya handler). Express middleware next() — Chain. Foyda: moslashuvchan zanjir (bosqich qo'shish/olib tashlash oson).

2.12. Command (buyruq) — behavioral

typescript
// Command — amalni obyekt sifatida (navbat, undo, log)
interface Buyruq {
  bajar(): Promise<void>;
  bekor?(): Promise<void>;                            // undo
}
class EmailYuborBuyruq implements Buyruq {
  constructor(private email: string) {}
  async bajar() { /* email yubor */ }
}
class Navbat {
  private buyruqlar: Buyruq[] = [];
  qosh(b: Buyruq) { this.buyruqlar.push(b); }
  async bajar() { for (const b of this.buyruqlar) await b.bajar(); }
}

Command — amalni obyekt sifatida o'rash (parametrlash, navbat, undo, log). Amal ma'lumot bo'ladi (saqlash, kechiktirish mumkin). BullMQ job 8.22-bob, CQRS command 9.7-bob, undo/redo uchun. NestJS CQRS moduli — Command pattern. Foyda: amalni saqlash/navbatlash/qaytarish.

2.13. Repository pattern (ma'lumotga kirish)

typescript
// Repository — ma'lumotga kirishni abstraksiyalash (domen entity qaytaradi)
interface UserRepository {
  topById(id: number): Promise<User | null>;
  topByEmail(email: string): Promise<User | null>;
  saqla(user: User): Promise<User>;
}
// Implementatsiya — DB detali (TypeORM/Mongo — 8.3)
class TypeOrmUserRepository implements UserRepository {
  async topById(id: number) { /* TypeORM */ return null; }
  async topByEmail(email: string) { return null; }
  async saqla(user: User) { return user; }
}
// Service — repository'ga tayanadi (DB'ni bilmaydi — DIP)
class UserService {
  constructor(private repo: UserRepository) {}
}

Repository — ma'lumotga kirishni abstraksiyalash (domen entity qaytaradi — raw data emas). Biznes mantiq DB detalini (SQL/Mongo) bilmaydi (DIP — 9.1: 2.9). TypeORM/Mongoose repository 8.3-bob — shu pattern. DB almashtirsa — faqat implementatsiya o'zgaradi. Clean Architecture 9.3-bob asosiy pattern. Foyda: DB izolyatsiyasi, test (mock).

2.14. Dependency Injection (bog'liqlikni yuklash)

typescript
// DI — obyekt o'z bog'liqliklarini O'ZI yaratmaydi, tashqaridan oladi
//  DI'siz — service repository'ni o'zi yaratadi (qattiq bog'liqlik)
class UserServiceYomon {
  private repo = new TypeOrmUserRepository();          // qattiq bog'liq (test qiyin)
}

//  DI — bog'liqlik konstruktordan (interfeysga tayanadi — DIP 9.1)
class UserServiceYaxshi {
  constructor(private repo: UserRepository) {}         // tashqaridan yuklanadi
}

// Container — bog'liqliklarni yig'ib beradi (NestJS buni avtomatik qiladi)
const repo = new TypeOrmUserRepository();
const service = new UserServiceYaxshi(repo);           // container "inject" qiladi

Dependency Injection — obyekt o'z bog'liqliklarini o'zi yaratmaydi, tashqaridan (konstruktor orqali) oladi. Bu — DIP (9.1: 2.9)ning amaliy vositasi: kod konkret klassga emas, interfeysga tayanadi. NestJS'ning butun asosi shu — @Injectable, constructor(private x: Servis) 8.2-bob. DI container Singleton 2.2-bob + Factory 2.3-bob pattern'larini birlashtiradi. Foyda: bo'shashgan bog'lanish, test (mock oson), moslashuvchanlik. DI — pattern emas, balki printsip + texnika, lekin backend'da eng muhim amaliy g'oya.

2.15. Abstract Factory (fabrikalar oilasi) — creational

typescript
// Abstract Factory — BOG'LIQ obyektlar OILASINI yaratish (bitta konkret klass emas)
interface Tugma { chiz(): string; }
interface Oyna { chiz(): string; }

// UI oilasi 1 — Material
class MaterialTugma implements Tugma { chiz() { return "Material tugma"; } }
class MaterialOyna implements Oyna { chiz() { return "Material oyna"; } }
// UI oilasi 2 — iOS
class IosTugma implements Tugma { chiz() { return "iOS tugma"; } }
class IosOyna implements Oyna { chiz() { return "iOS oyna"; } }

// Abstract Factory — bir oilaning MOS elementlarini qaytaradi
interface UiFactory {
  tugmaYarat(): Tugma;
  oynaYarat(): Oyna;
}
class MaterialFactory implements UiFactory {
  tugmaYarat() { return new MaterialTugma(); }
  oynaYarat() { return new MaterialOyna(); }
}
class IosFactory implements UiFactory {
  tugmaYarat() { return new IosTugma(); }
  oynaYarat() { return new IosOyna(); }
}
// Klient bir oilani tanlaydi — hamma elementlar mos keladi
function ilova(factory: UiFactory) {
  return [factory.tugmaYarat().chiz(), factory.oynaYarat().chiz()];
}

Abstract Factory — bitta obyekt emas, bog'liq obyektlar oilasini yaratish (elementlar bir-biriga mos keladi). Factory Method 2.3-bob bitta obyekt yaratadi; Abstract Factory — bir necha bog'liq obyektni birga (Material tugma + Material oyna, aralashmaydi). Backend'da: bir DB provayder uchun mos repository'lar to'plami, bir muhit (test/prod) uchun mos servislar. Farqi (Factory Method'dan): Factory Method — bitta mahsulot, Abstract Factory — mahsulotlar oilasi. Foyda: mos elementlar kafolati. Kamchilik: yangi mahsulot turi qo'shish qiyin (interfeys o'zgaradi).

2.16. Prototype (klonlash) — creational

typescript
// Prototype — mavjud obyektni KLONLASH orqali yangi yaratish (noldan emas)
interface Klonlanadigan<T> {
  klon(): T;
}
class Sozlama implements Klonlanadigan<Sozlama> {
  constructor(
    public tema: string,
    public til: string,
    public ruxsatlar: string[],
  ) {}
  klon(): Sozlama {
    // Chuqur nusxa (ruxsatlar massivini ham nusxalash)
    return new Sozlama(this.tema, this.til, [...this.ruxsatlar]);
  }
}
const asos = new Sozlama("dark", "uz", ["read"]);
const foydalanuvchi = asos.klon();                     // asosdan nusxa
foydalanuvchi.ruxsatlar.push("write");                 // asosga ta'sir qilmaydi

Prototype — yangi obyektni noldan yaratish o'rniga, mavjudini klonlash (nusxa olish). Obyekt yaratish qimmat bo'lganda yoki tayyor shablondan bir necha o'xshash obyekt kerak bo'lganda. JS'da structuredClone, Object.assign, spread ({...obj}) — shu g'oya. Ehtiyot: sayoz (shallow) vs chuqur (deep) nusxa — ichki obyekt/massiv umumiy qolmasligi kerak. Foyda: qimmat yaratishni tejash, tayyor shablon. Backend'da: default config'dan foydalanuvchi config'i, test fixture nusxalari.

2.17. Bridge (abstraksiya implementatsiya) — structural

typescript
// Bridge — abstraksiyani implementatsiyadan AJRATISH (ikkalasi mustaqil o'zgaradi)
// Implementatsiya tomoni — qanday yuboriladi
interface YuborishKanali {
  yubor(matn: string): void;
}
class EmailKanal implements YuborishKanali { yubor(m: string) { /* email */ } }
class SmsKanal implements YuborishKanali { yubor(m: string) { /* sms */ } }

// Abstraksiya tomoni — nima yuboriladi (kanalga "ko'prik")
abstract class Bildirishnoma {
  constructor(protected kanal: YuborishKanali) {}      // ko'prik (bridge)
  abstract yubor(): void;
}
class OddiyBildirishnoma extends Bildirishnoma {
  constructor(kanal: YuborishKanali, private matn: string) { super(kanal); }
  yubor() { this.kanal.yubor(this.matn); }
}
class ShoshilinchBildirishnoma extends Bildirishnoma {
  constructor(kanal: YuborishKanali, private matn: string) { super(kanal); }
  yubor() { this.kanal.yubor("[SHOSHILINCH] " + this.matn); }
}
// 2 tur × 2 kanal = 4 kombinatsiya, lekin 2+2 klass (meros portlashi yo'q)

Bridge — abstraksiyani (nima) implementatsiyadan (qanday) ajratadi, ikkalasi mustaqil rivojlanadi. Muammo: EmailShoshilinch, SmsShoshilinch, EmailOddiy... — meros kombinatsiyalari portlaydi (M×N klass). Bridge kompozitsiya bilan M+N ga tushiradi. Farqi (Adapter'dan): Adapter mavjud mos kelmagan interfeyslarni keyin bog'laydi; Bridge tizimni oldindan ikki mustaqil o'qqa ajratib loyihalaydi. Foyda: ikki o'lcham mustaqil kengayadi. Backend'da: bildirishnoma turi × kanal, hisobot turi × format.

2.18. Composite (daraxt tuzilma) — structural

typescript
// Composite — yagona obyekt va guruhni BIR XIL ishlatish (daraxt: fayl/papka)
interface FsElement {
  hajm(): number;                                      // umumiy interfeys
}
// Barg (leaf) — yagona element
class Fayl implements FsElement {
  constructor(private oz: number) {}
  hajm() { return this.oz; }
}
// Kompozit — ichida bolalar (fayl yoki papka)
class Papka implements FsElement {
  private bolalar: FsElement[] = [];
  qosh(el: FsElement) { this.bolalar.push(el); }
  hajm(): number {                                     // rekursiv yig'indi
    return this.bolalar.reduce((s, b) => s + b.hajm(), 0);
  }
}
const ildiz = new Papka();
ildiz.qosh(new Fayl(100));
const ichki = new Papka();
ichki.qosh(new Fayl(50));
ildiz.qosh(ichki);
console.log(ildiz.hajm());                             // 150 (rekursiv)

Composite — yagona obyekt (barg) va obyektlar guruhini (kompozit) bir xil interfeys orqali ishlatish (daraxtsimon tuzilma). Klient Faylmi yoki Papkami — farqiga bormaydi, hajm() chaqiradi. Rekursiv tuzilmalar: fayl tizimi, tashkilot ierarxiyasi, UI komponentlar daraxti, menyu-submenu, kategoriya daraxti. Foyda: yagona/guruhni birdek ishlash, rekursiya soddalashadi. Backend'da: nested kategoriya, ruxsatlar daraxti, tashkiliy tuzilma.

2.19. Flyweight (umumiy holat) — structural

typescript
// Flyweight — ko'p o'xshash obyektlar UMUMIY holatni bo'lishadi (xotira tejash)
// Umumiy (ichki) holat — bir marta yaratiladi, bo'lishiladi
class Belgi {
  constructor(public shrift: string, public rang: string) {}
}
// Flyweight fabrikasi — bir xil holatni qayta ishlatadi
class BelgiFactory {
  private kesh = new Map<string, Belgi>();
  ol(shrift: string, rang: string): Belgi {
    const kalit = `${shrift}:${rang}`;
    if (!this.kesh.has(kalit)) this.kesh.set(kalit, new Belgi(shrift, rang));
    return this.kesh.get(kalit)!;                       // umumiy instance
  }
}
const factory = new BelgiFactory();
const a = factory.ol("Arial", "qora");
const b = factory.ol("Arial", "qora");
console.log(a === b);                                  // true (bir instance, tejash)

Flyweight — juda ko'p o'xshash obyektlar umumiy (ichki) holatni bo'lishib, xotirani tejaydi. Faqat farqli (tashqi) holat alohida saqlanadi. Millionlab obyekt kerak bo'lganda (matn muharriridagi harflar, o'yindagi zarralar, xaritadagi belgilar). Amalda kamdan-kam qo'l bilan yoziladi; ko'pincha kesh/pool ko'rinishida. Backend'da: string interning, ulanish pool, takrorlanuvchi konfiguratsiya obyektlari. Foyda: xotira tejash. Kamchilik: murakkablik — faqat haqiqiy xotira muammosida.

2.20. Iterator (elementlarni aylanish) — behavioral

typescript
// Iterator — kolleksiya elementlarini ICHKI tuzilmani ochmasdan aylanish
// TS'da tabiiy: Symbol.iterator (for...of ishlaydi)
class Sahifalangan<T> implements Iterable<T> {
  constructor(private elementlar: T[], private sahifaHajmi: number) {}
  *[Symbol.iterator](): Iterator<T> {                  // generator iterator
    for (const el of this.elementlar) yield el;
  }
  *sahifalar(): Generator<T[]> {                       // sahifa-sahifa
    for (let i = 0; i < this.elementlar.length; i += this.sahifaHajmi) {
      yield this.elementlar.slice(i, i + this.sahifaHajmi);
    }
  }
}
const ro'yxat = new Sahifalangan([1, 2, 3, 4, 5], 2);
for (const el of ro'yxat) { /* har element */ }         // Iterator
for (const sahifa of ro'yxat.sahifalar()) { /* [1,2],[3,4],[5] */ }

Iterator — kolleksiya elementlarini ichki tuzilmani ochmasdan ketma-ket aylanish. JS/TS'da bu tilga qurilgan: Symbol.iterator, for...of, generator (function*, yield) — siz allaqachon Iterator ishlatib kelasiz. Qo'lda yozish kamdan-kam kerak. Backend'da: sahifalash (pagination), oqim (stream) bilan katta ma'lumotni bo'lib o'qish, kursorli DB natijalari. Foyda: aylanish mantig'i ajratilgan, xotira tejash (lazy — generator). Zamonaviy JS'da klassik Iterator klassi o'rniga generator ishlatiladi.

2.21. Mediator (markazlashgan aloqa) — behavioral

typescript
// Mediator — obyektlar bir-biri bilan TO'G'RIDAN emas, MEDIATOR orqali gaplashadi
interface Mediator {
  xabar(kimdan: string, hodisa: string, data?: any): void;
}
class ChatMediator implements Mediator {
  private a'zolar = new Map<string, Foydalanuvchi>();
  qoshil(u: Foydalanuvchi) { this.a'zolar.set(u.nom, u); }
  xabar(kimdan: string, hodisa: string, data?: any) {
    // Markazda marshrutlash (a'zolar bir-birini bilmaydi)
    for (const [nom, u] of this.a'zolar) {
      if (nom !== kimdan) u.qabulQil(kimdan, data);
    }
  }
}
class Foydalanuvchi {
  constructor(public nom: string, private mediator: Mediator) {}
  yubor(matn: string) { this.mediator.xabar(this.nom, "xabar", matn); }
  qabulQil(kimdan: string, matn: string) { /* ko'rsatish */ }
}

Mediator — ko'p obyekt bir-biri bilan to'g'ridan-to'g'ri emas, markaziy vositachi (mediator) orqali gaplashadi. Muammo: N obyekt bir-birini bilsa — N² bog'lanish (chalkash). Mediator hammani markazga ulaydi (yulduz topologiya). Farqi (Observer'dan): Observer bir yo'nalishli (subject kuzatuvchilar); Mediator ko'p obyektlar orasidagi ikki yo'nalishli murakkab aloqani boshqaradi. Backend'da: chat xonasi, WebSocket gateway 8.18-bob, UI komponentlar orasidagi muvofiqlashtirish. Foyda: bog'lanish kamayadi. Kamchilik: mediator "God Object"ga aylanishi mumkin 2.26-bob.

2.22. Memento (holatni saqlash/tiklash) — behavioral

typescript
// Memento — obyekt HOLATINI kapsulani buzmasdan saqlab, keyin tiklash (undo)
class Memento {
  constructor(public readonly holat: string) {}         // o'zgarmas snapshot
}
class Muharrir {
  private matn = "";
  yoz(qism: string) { this.matn += qism; }
  saqla(): Memento { return new Memento(this.matn); }   // snapshot
  tikla(m: Memento) { this.matn = m.holat; }            // qaytarish
  ko'rsat() { return this.matn; }
}
// Caretaker — snapshot'larni saqlaydi (tarix)
const muharrir = new Muharrir();
const tarix: Memento[] = [];
muharrir.yoz("Salom");
tarix.push(muharrir.saqla());                          // saqla
muharrir.yoz(" dunyo");
muharrir.tikla(tarix.pop()!);                          // undo  "Salom"

Memento — obyekt ichki holatini (kapsulani buzmasdan) snapshot sifatida saqlab, keyin o'sha holatga qaytarish. Bu — undo/redo mexanizmi asosi. Uchta rol: originator (holat egasi), memento (o'zgarmas snapshot), caretaker (snapshot'lar tarixi). Backend'da: hujjat versiyalari, tranzaksiya rollback, form draft saqlash, o'yin holati. Command 2.12-bob bilan birga undo/redo tizimini quradi. Foyda: kapsula buzilmaydi (tashqi kod ichki holatni ko'rmaydi). Kamchilik: ko'p snapshot — xotira.

2.23. State (holatga qarab xulq) — behavioral

typescript
// State — obyekt xulqi ICHKI HOLATIGA qarab o'zgaradi (if/switch o'rniga klasslar)
interface BuyurtmaHolati {
  tola(b: Buyurtma): void;
  bekorQil(b: Buyurtma): void;
}
class YangiHolat implements BuyurtmaHolati {
  tola(b: Buyurtma) { b.holatniOzgartir(new TolanganHolat()); }
  bekorQil(b: Buyurtma) { b.holatniOzgartir(new BekorHolat()); }
}
class TolanganHolat implements BuyurtmaHolati {
  tola(b: Buyurtma) { throw new Error("Allaqachon to'langan"); }
  bekorQil(b: Buyurtma) { throw new Error("To'langanni bekor qilib bo'lmaydi"); }
}
class BekorHolat implements BuyurtmaHolati {
  tola(b: Buyurtma) { throw new Error("Bekor qilingan"); }
  bekorQil(b: Buyurtma) { throw new Error("Allaqachon bekor"); }
}
class Buyurtma {
  private holat: BuyurtmaHolati = new YangiHolat();
  holatniOzgartir(h: BuyurtmaHolati) { this.holat = h; }
  tola() { this.holat.tola(this); }                    // holatga topshiradi
  bekorQil() { this.holat.bekorQil(this); }
}

State — obyekt ichki holatiga qarab xulqini o'zgartiradi (obyekt go'yo klassini almashtiradigandek). Har holat — alohida klass, o'z qoidalari bilan. Katta switch(holat) o'rniga (yangi holat eski o'zgarmaydi — OCP 9.1). Farqi (Strategy'dan): tuzilmasi bir xil, lekin State'da holatlar bir-birini almashtiradi (o'tishlarni o'zi boshqaradi), Strategy'da algoritmni tashqaridan klient tanlaydi. Backend'da: buyurtma/to'lov holatlari (state machine), hujjat workflow, ulanish holati. Foyda: holat mantig'i tartibli, noto'g'ri o'tish oldini oladi.

2.24. Template Method (algoritm skeleti) — behavioral

typescript
// Template Method — algoritm SKELETI bazada, qadamlar vorislarda aniqlanadi
abstract class MalumotEksporti {
  // Template metod — umumiy tartib (o'zgarmas skelet)
  eksport(malumot: any[]): string {
    const boshlanish = this.sarlavha();
    const tana = malumot.map((r) => this.qator(r)).join("\n");
    const oxir = this.yakun();
    return [boshlanish, tana, oxir].filter(Boolean).join("\n");
  }
  protected abstract sarlavha(): string;               // vorislar aniqlaydi
  protected abstract qator(r: any): string;
  protected yakun(): string { return ""; }             // ixtiyoriy (hook)
}
class CsvEksport extends MalumotEksporti {
  protected sarlavha() { return "id,nom"; }
  protected qator(r: any) { return `${r.id},${r.nom}`; }
}
class JsonEksport extends MalumotEksporti {
  protected sarlavha() { return "["; }
  protected qator(r: any) { return JSON.stringify(r) + ","; }
  protected yakun() { return "]"; }
}

Template Method — algoritmning umumiy skeleti (qadamlar tartibi) baza klassda qat'iy, ayrim qadamlar vorislarda aniqlanadi. Umumiy jarayon bir xil, faqat detallar farq qiladi (eksport tartibi bir xil — format har xil). Farqi (Strategy'dan): Template Method meros bilan (kompilyatsiyada qat'iy), Strategy kompozitsiya bilan (runtime'da almashtiriladi). Backend'da: ETL bosqichlari, so'rov ishlash pipeline'i, test setup/teardown. Foyda: kod takrori kamayadi (umumiy tartib bir joyda), DRY. Kamchilik: meros qattiqligi.

2.25. Visitor (tuzilmaga yangi amal qo'shish) — behavioral

typescript
// Visitor — obyektlar tuzilmasiga ULARNI o'zgartirmasdan yangi amal qo'shish
interface Visitor {
  matnKel(n: MatnTugun): string;
  rasmKel(n: RasmTugun): string;
}
interface Tugun { qabulQil(v: Visitor): string; }      // visitor'ni "qabul qiladi"
class MatnTugun implements Tugun {
  constructor(public matn: string) {}
  qabulQil(v: Visitor) { return v.matnKel(this); }      // ikki tomonlama yuborish
}
class RasmTugun implements Tugun {
  constructor(public url: string) {}
  qabulQil(v: Visitor) { return v.rasmKel(this); }
}
// Yangi amal — tugunlarni o'zgartirmasdan (masalan HTML render)
class HtmlVisitor implements Visitor {
  matnKel(n: MatnTugun) { return `<p>${n.matn}</p>`; }
  rasmKel(n: RasmTugun) { return `<img src="${n.url}">`; }
}
const tugunlar: Tugun[] = [new MatnTugun("Salom"), new RasmTugun("a.png")];
const html = tugunlar.map((t) => t.qabulQil(new HtmlVisitor())).join("");

Visitor — obyektlar tuzilmasiga (turli tugun turlariga) ularni o'zgartirmasdan yangi amal qo'shish. Yangi amal (HTML render, validatsiya, statistika) — yangi visitor klassi, tugunlar tegmaydi. Muammosi: yangi tugun turi qo'shilsa — hamma visitor o'zgaradi (aksi OCP). Shuning uchun tugun turlari barqaror, amallar tez-tez qo'shiladigan holatlarda foydali. Backend'da: AST ishlash (kompilyator, linter), hujjat daraxti render, murakkab hisobotlar. Eng murakkab pattern — kamdan-kam kerak, TS'da ko'pincha switch(tur) yoki discriminated union soddaroq. Foyda: amallar ajratilgan.

2.26. Pattern'lardan haddan oshmaslik (anti-pattern)

text
   Pattern — vosita, maqsad emas:
  - Over-engineering (oddiy muammoga murakkab pattern)
  - "Pattern uchun pattern" (kerak emas joyda)
  - Pattern nomini bilish ≠ to'g'ri ishlatish

  ANTI-PATTERN (qochish kerak):
  - God Object (hamma narsa bir klassda — SRP buzilishi)
  - Spaghetti code (chalkash bog'lanish)
  - Magic numbers/strings (konstanta emas)

  Qoida: oddiy yechim  kerak bo'lsa pattern (KISS, YAGNI — 9.1: 2.12)

Pattern'dan oshmaslik: pattern — vosita (maqsad emas). Oddiy muammoga murakkab pattern — over-engineering. "Pattern uchun pattern" — yomon. Anti-patternlar (qochish): God Object (SRP buzilishi), spaghetti (chalkash), magic number. Qoida: oddiy yechim muammo bo'lsa pattern (KISS/YAGNI — 9.1: 2.12). Pattern'ni tanish muhim, lekin to'g'ri ishlatish muhimroq.

2.27. Best practices (pattern)

text
   Pattern'ni MUAMMOGA mosla (har joyga emas — 2.26)
   Singleton — NestJS provider (DI afzal — 2.2)
   Strategy/Factory — OCP (o'zgaruvchan tur — 2.3, 2.9)
   Observer — event-driven (5.4, 8.16 — 2.10)
   Chain — middleware/guard (8.6 — 2.11)
   Repository — DB izolyatsiya (8.3 — 2.13)
   Adapter — tashqi integratsiya 2.5-bob
   Anti-pattern'dan qoch (God Object, spaghetti — 2.26)
   Umumiy til (jamoa — pattern nomlari)

3. Sintaksis — tez ma'lumotnoma

typescript
// Creational
Singleton:  static getInstance()                     // bitta instance (2.2)
Factory:    static yarat(tur): Interface             // yaratishni markazlash (2.3)
Builder:    .filter().sarala().build()               // bosqichma-bosqich (2.4)

// Structural
Adapter:    class A implements Our { constructor(private tashqi) }   // moslash (2.5)
Decorator:  class D implements I { constructor(private wrapped: I) } // o'rash (2.6)
Facade:     bitta metod  ko'p servis 2.7-bob

// Behavioral
Strategy:   constructor(private strategiya: IStrategy)   // almashtiriladigan 2.9-bob
Observer:   obuna(k) / xabarBer(data)                    // pub-sub 2.10-bob
Chain:      keyingi?.ishla()                             // zanjir 2.11-bob
Repository: interface Repo { topById(): Promise<Entity> }   // DB abstraksiya (2.13)

4. Batafsil kod namunalari

Misol 1 — Factory + Strategy (to'lov — 2.3, 2.9)

typescript
// Strategy — to'lov algoritmlari
interface TolovStrategiyasi {
  tolov(summa: number): Promise<{ success: boolean; tranzaksiyaId: string }>;
}
class ClickStrategiya implements TolovStrategiyasi {
  async tolov(summa: number) { return { success: true, tranzaksiyaId: "click_123" }; }
}
class PaymeStrategiya implements TolovStrategiyasi {
  async tolov(summa: number) { return { success: true, tranzaksiyaId: "payme_456" }; }
}
class UzumStrategiya implements TolovStrategiyasi {    // YANGI — eski tegmaydi (OCP)
  async tolov(summa: number) { return { success: true, tranzaksiyaId: "uzum_789" }; }
}

// Factory — strategiyani yaratish
class TolovFactory {
  private static strategiyalar = new Map<string, () => TolovStrategiyasi>([
    ["click", () => new ClickStrategiya()],
    ["payme", () => new PaymeStrategiya()],
    ["uzum", () => new UzumStrategiya()],
  ]);
  static yarat(tur: string): TolovStrategiyasi {
    const yaratuvchi = this.strategiyalar.get(tur);
    if (!yaratuvchi) throw new Error(`Noma'lum to'lov: ${tur}`);
    return yaratuvchi();
  }
}

// Service
class TolovService {
  async tolovBajar(tur: string, summa: number) {
    const strategiya = TolovFactory.yarat(tur);       // Factory
    return strategiya.tolov(summa);                   // Strategy
  }
}

Misol 2 — Observer (event-driven — 2.10)

typescript
// Buyurtma yaratilganda — ko'p tizim xabardor (loose coupling)
type Hodisa = "buyurtma_yaratildi" | "buyurtma_tolandi";

class HodisaEmitter {
  private kuzatuvchilar = new Map<Hodisa, ((data: any) => void)[]>();

  on(hodisa: Hodisa, handler: (data: any) => void) {
    if (!this.kuzatuvchilar.has(hodisa)) this.kuzatuvchilar.set(hodisa, []);
    this.kuzatuvchilar.get(hodisa)!.push(handler);
  }
  emit(hodisa: Hodisa, data: any) {
    this.kuzatuvchilar.get(hodisa)?.forEach((h) => h(data));
  }
}

const emitter = new HodisaEmitter();
// Kuzatuvchilar (bir-birini bilmaydi)
emitter.on("buyurtma_yaratildi", (d) => console.log("Email yuborildi", d.id));
emitter.on("buyurtma_yaratildi", (d) => console.log("SMS yuborildi", d.id));
emitter.on("buyurtma_yaratildi", (d) => console.log("Statistika yangilandi", d.id));
// Buyurtma service
emitter.emit("buyurtma_yaratildi", { id: 1 });        // hammaga xabar
//  Node.js EventEmitter 5.4-bob, NestJS @EventPattern 8.16-bob — shu g'oya

Misol 3 — Repository (DB abstraksiya — 2.13)

typescript
// Domen entity
class Product {
  constructor(public id: number, public nom: string, public narx: number, public zaxira: number) {}
  zaxiradaBor(miqdor: number): boolean { return this.zaxira >= miqdor; }   // biznes mantiq
}

// Repository interfeysi (domen qatlamida — DB'ni bilmaydi)
interface ProductRepository {
  topById(id: number): Promise<Product | null>;
  topByKategoriya(kategoriya: string): Promise<Product[]>;
  saqla(product: Product): Promise<Product>;
}

// Implementatsiya (infratuzilma qatlami — TypeORM)
class TypeOrmProductRepository implements ProductRepository {
  async topById(id: number): Promise<Product | null> {
    // const row = await this.repo.findOneBy({ id });  (8.3)
    // return row ? new Product(row.id, row.nom, row.narx, row.zaxira) : null;
    return null;
  }
  async topByKategoriya(k: string) { return []; }
  async saqla(p: Product) { return p; }
}

// Implementatsiya (MongoDB — almashtirsa bo'ladi — DIP)
class MongoProductRepository implements ProductRepository {
  async topById(id: number) { return null; }          // Mongoose (8.13)
  async topByKategoriya(k: string) { return []; }
  async saqla(p: Product) { return p; }
}
// Service repository interfeysiga tayanadi (TypeORM/Mongo — farqi yo'q)

Misol 4 — Adapter (tashqi to'lov — 2.5)

typescript
// Bizning interfeys
interface ToloyTizimi {
  tolov(summa: number, karta: string): Promise<boolean>;
}

// Tashqi Click SDK (boshqa interfeys)
class ClickSDK {
  createPayment(amount: number, cardToken: string, merchantId: string): Promise<{ status: string }> {
    return Promise.resolve({ status: "success" });
  }
}

// Adapter — Click SDK'ni bizning interfeysga
class ClickAdapter implements ToloyTizimi {
  constructor(private sdk: ClickSDK, private merchantId: string) {}
  async tolov(summa: number, karta: string): Promise<boolean> {
    const natija = await this.sdk.createPayment(summa, karta, this.merchantId);
    return natija.status === "success";               // moslashtirish
  }
}
//  Click'ni Payme'ga almashtirsa: yangi PaymeAdapter (qolgan kod tegmaydi)

Misol 5 — Decorator (funksiya qo'shish — 2.6)

typescript
// Bildirishnoma — qo'shimchalar bilan o'rash
interface Bildirishnoma {
  yubor(matn: string): Promise<void>;
}
class AsosiyBildirishnoma implements Bildirishnoma {
  async yubor(matn: string) { console.log("Yuborildi:", matn); }
}
// Decorator — log qo'shadi
class LogDecorator implements Bildirishnoma {
  constructor(private wrapped: Bildirishnoma) {}
  async yubor(matn: string) {
    console.log("Log: yuborilmoqda");                 // qo'shimcha
    await this.wrapped.yubor(matn);
    console.log("Log: yuborildi");
  }
}
// Decorator — qayta urinish qo'shadi
class RetryDecorator implements Bildirishnoma {
  constructor(private wrapped: Bildirishnoma, private urinish = 3) {}
  async yubor(matn: string) {
    for (let i = 0; i < this.urinish; i++) {
      try { return await this.wrapped.yubor(matn); }
      catch (e) { if (i === this.urinish - 1) throw e; }
    }
  }
}
// Kombinatsiya (o'rash)
let b: Bildirishnoma = new AsosiyBildirishnoma();
b = new RetryDecorator(b);                            // + qayta urinish
b = new LogDecorator(b);                              // + log

Misol 6 — Chain of Responsibility (validatsiya — 2.11)

typescript
// So'rov validatsiya zanjiri (middleware kabi — 8.6)
abstract class Validator {
  private keyingi?: Validator;
  keyingiQoy(v: Validator): Validator { this.keyingi = v; return v; }
  protected keyingiTekshir(sorov: any): boolean {
    return this.keyingi ? this.keyingi.tekshir(sorov) : true;
  }
  abstract tekshir(sorov: any): boolean;
}
class AuthValidator extends Validator {
  tekshir(sorov: any) {
    if (!sorov.token) throw new Error("Token yo'q");
    return this.keyingiTekshir(sorov);
  }
}
class RoleValidator extends Validator {
  tekshir(sorov: any) {
    if (sorov.rol !== "admin") throw new Error("Admin kerak");
    return this.keyingiTekshir(sorov);
  }
}
class DataValidator extends Validator {
  tekshir(sorov: any) {
    if (!sorov.data) throw new Error("Data yo'q");
    return this.keyingiTekshir(sorov);
  }
}
// Zanjir qurish
const auth = new AuthValidator();
auth.keyingiQoy(new RoleValidator()).keyingiQoy(new DataValidator());
auth.tekshir({ token: "x", rol: "admin", data: {} }); // auth  role  data

Misol 7 — Singleton (NestJS kontekst — 2.2)

typescript
// Klassik Singleton (DI'siz — eski uslub)
class Logger {
  private static instance: Logger;
  private constructor() {}
  static getInstance(): Logger {
    if (!Logger.instance) Logger.instance = new Logger();
    return Logger.instance;
  }
  log(matn: string) { console.log(`[${new Date().toISOString()}] ${matn}`); }
}

//  NestJS uslubi — provider default Singleton (DI bilan — afzal, 8.2)
@Injectable()
export class LoggerService {                          // avtomatik singleton (8.2: 2.10)
  log(matn: string) { console.log(matn); }
}
// constructor(private logger: LoggerService) — bir xil instance (DI)
//  DI singleton'i test'da oson mock (klassik singleton — qiyin)

Misol 8 — Builder (query — 2.4)

typescript
// Murakkab so'rov builder (TypeORM QueryBuilder ruhida — 6.13)
class QueryBuilder<T> {
  private shartlar: string[] = [];
  private saralash?: string;
  private limitSoni = 100;
  private offsetSoni = 0;

  where(shart: string): this { this.shartlar.push(shart); return this; }
  orderBy(maydon: string, yon: "ASC" | "DESC" = "ASC"): this {
    this.saralash = `${maydon} ${yon}`; return this;
  }
  limit(n: number): this { this.limitSoni = n; return this; }
  offset(n: number): this { this.offsetSoni = n; return this; }
  build(): string {
    let sql = "SELECT * FROM table";
    if (this.shartlar.length) sql += ` WHERE ${this.shartlar.join(" AND ")}`;
    if (this.saralash) sql += ` ORDER BY ${this.saralash}`;
    sql += ` LIMIT ${this.limitSoni} OFFSET ${this.offsetSoni}`;
    return sql;
  }
}
const query = new QueryBuilder()
  .where("rol = 'admin'")
  .where("faol = true")
  .orderBy("createdAt", "DESC")
  .limit(20)
  .build();

Misol 9 — Facade (buyurtma — 2.7)

typescript
// Murakkab buyurtma jarayonini soddalashtirish (use-case — 9.3 ko'prik)
class BuyurtmaFacade {
  constructor(
    private inventory: InventoryService,
    private payment: PaymentService,
    private orders: OrderRepository,
    private events: HodisaEmitter,                    // Observer (Misol 2)
  ) {}

  async buyurtmaYakunla(dto: CreateOrderDto): Promise<Order> {
    // Klient bu murakkablikni ko'rmaydi (bitta metod)
    await this.inventory.bandQil(dto.items);
    const tolov = await this.payment.tolov(dto.tolovTuri, dto.summa);
    if (!tolov.success) {
      await this.inventory.bekorQil(dto.items);       // kompensatsiya (9.4 Saga)
      throw new Error("To'lov amalga oshmadi");
    }
    const order = await this.orders.saqla(dto as any);
    this.events.emit("buyurtma_yaratildi", order);    // Observer  email/sms
    return order;
  }
}
// Klient: facade.buyurtmaYakunla(dto) — ichki 4 tizimni bilmaydi

Misol 10 — Pattern'lar NestJS'da (umumlashtirish)

text
  NestJS'da ishlatilgan pattern'lar (nomini bilmasdan):
  ┌────────────────────────┬──────────────────────────────────┐
  │ Singleton              │ provider (default scope — 8.2)    │
  │ Factory               │ useFactory (8.2: 2.6)             │
  │ Strategy              │ to'lov/auth strategiyalari 8.9-bob  │
  │ Observer              │ @EventPattern, EventEmitter 8.16-bob│
  │ Chain of Resp.        │ middleware/guard/pipe 8.6-bob      │
  │ Decorator             │ @Injectable, @Get, ... 7.6-bob     │
  │ Repository            │ TypeORM/Mongoose repo 8.3-bob      │
  │ Adapter               │ Express/Fastify adapter 8.1-bob     │
  │ Proxy                 │ guard (himoya), cache 8.15-bob     │
  │ Facade                │ service (controller uchun — 8.1) │
  └────────────────────────┴──────────────────────────────────┘
   NestJS — pattern'lar ustiga qurilgan framework

5. To'g'ri va noto'g'ri holatlar

1) Pattern uchun pattern

text
 oddiy muammoga 5 ta pattern (over-engineering — 2.26)
 oddiy yechim  kerak bo'lsa pattern (KISS)

2) Klassik Singleton (DI o'rniga)

text
 getInstance() (global holat, test qiyin — 2.2)
 NestJS provider (DI singleton — 2.2, Misol 7)

3) switch/if (Strategy o'rniga)

text
 katta switch (OCP buzilishi — 9.1)
 Strategy + Factory (2.9, Misol 1)

4) Service'da DB to'g'ridan (Repository o'rniga)

text
 service'da SQL/query (bog'liqlik — 2.13)
 Repository (DB abstraksiya)

5) God Object (anti-pattern)

text
 hamma narsa bir klassda (SRP buzilishi — 2.26)
 ajratilgan (SOLID — 9.1)

6. Keng tarqalgan xatolar va yechimlari

Xato 1 — Pattern haddan ko'p

Sababi: har joyga pattern (over-engineering — 2.26). Yechimi: muammoga mosla; KISS/YAGNI.

Xato 2 — Singleton test'da muammo

Sababi: global holat 2.2-bob. Yechimi: DI singleton (NestJS — mock oson).

Xato 3 — Strategy'ni if bilan

Sababi: Strategy tushunilmagan. Yechimi: interfeys + klasslar (Misol 1).

Xato 4 — Observer xotira sizishi

Sababi: obuna olib tashlanmagan (off yo'q). Yechimi: unsubscribe; cleanup.

Xato 5 — Repository raw data qaytaradi

Sababi: domen entity emas 2.13-bob. Yechimi: entity qaytar (DTO/raw emas).

Xato 6 — Pattern nomini bilib, noto'g'ri ishlatish

Sababi: "nima" bilan "qachon" farqi. Yechimi: muammoni tushun, mos pattern 2.1-bob.


7. Integratsiya — bu mavzu stack'ning qayerida uchraydi

  • SOLID 9.1-bob: pattern'lar SOLID'ni amalga oshiradi.
  • NestJS (8): DI/middleware/guard — pattern'lar (Misol 10).
  • EventEmitter 5.4-bob: Observer.
  • Repository 8.3-bob: DB abstraksiya.
  • Strategy 8.9-bob: auth/to'lov.
  • Chain 8.6-bob: middleware/guard.
  • Clean Architecture 9.3-bob: Repository, Facade.
  • CQRS 9.7-bob: Command.

8. Eng yaxshi amaliyotlar (best practices)

  • Pattern'ni muammoga mosla (har joyga emas — 2.26).
  • Singleton — NestJS provider (DI afzal — 2.2).
  • Strategy/Factory — OCP (o'zgaruvchan tur — 2.3, 2.9).
  • Observer — event-driven (5.4, 8.16 — 2.10).
  • Chain — middleware/guard (8.6 — 2.11).
  • Repository — DB izolyatsiya (8.3 — 2.13).
  • Adapter — tashqi integratsiya 2.5-bob.
  • Anti-pattern'dan qoch (God Object, spaghetti — 2.26).
  • Umumiy til (jamoa — pattern nomlari).
  • Decorator/Facade (kengaytirish/soddalik — 2.6, 2.7).

9. Amaliy loyiha: "Pattern'lar bilan To'lov Tizimi"

Design pattern'larni amalda mustahkamlash.

Maqsad

To'lov/bildirishnoma tizimini bir nechta pattern bilan qurish: Strategy, Factory, Observer, Adapter, Repository.

Talablar (requirements)

  1. Strategy: to'lov usullari (Click/Payme/Uzum — Misol 1, 2.9).
  2. Factory: to'lov yaratish (Misol 1, 2.3).
  3. Observer: to'lov hodisalari email/SMS/log (Misol 2, 2.10).
  4. Adapter: tashqi to'lov SDK (Misol 4, 2.5).
  5. Repository: tranzaksiya saqlash (Misol 3, 2.13).
  6. Decorator: retry/log o'rash (Misol 5, 2.6).
  7. Chain: validatsiya zanjiri (Misol 6, 2.11).
  8. Facade: to'liq to'lov jarayoni (Misol 9, 2.7).
  9. Singleton: logger/config (DI — Misol 7, 2.2).
  10. Balans: over-engineering'dan qochish 2.26-bob.

Maslahatlar (hint)

  • Strategy + Factory birga (OCP — Misol 1).
  • Observer: loose coupling (2.10, 4-xato unsubscribe).
  • Repository: entity qaytar (2.13, 5-xato).
  • Singleton: NestJS provider (2.2, 2-xato).
  • Pattern muammoga (2.26, 1-xato).

"Tayyor" mezonlari (acceptance criteria)

  • Strategy (to'lov usullari).
  • Factory.
  • Observer (hodisalar).
  • Adapter (tashqi SDK).
  • Repository.
  • Decorator.
  • Chain (validatsiya).
  • Facade.
  • Singleton (DI).
  • Balans (over-engineering yo'q).

Yechim kodi ataylab berilmagan — bu loyihani o'zingiz yozib ko'ring.


10. Xulosa va keyingi bobga ko'prik

Bu bobda design pattern'larni chuqur o'rgandik:

  • Tushuncha (isbotlangan yechim, 3 tur — 2.1); Creational (Singleton — 2.2, Factory — 2.3, Builder — 2.4, Abstract Factory — 2.15, Prototype — 2.16).
  • Structural (Adapter — 2.5, Decorator — 2.6, Facade — 2.7, Proxy — 2.8, Bridge — 2.17, Composite — 2.18, Flyweight — 2.19).
  • Behavioral (Strategy — 2.9, Observer — 2.10, Chain — 2.11, Command — 2.12, Iterator — 2.20, Mediator — 2.21, Memento — 2.22, State — 2.23, Template Method — 2.24, Visitor — 2.25); Repository 2.13-bob, DI 2.14-bob.
  • Anti-pattern'dan qochish 2.26-bob; NestJS'da pattern'lar (Misol 10).

Keyingi bob — 9.3-bob: Clean Architecture, Layered, Hexagonal. SOLID va pattern'larni bildik; endi ularni butun ilova darajasida tashkil qiladigan arxitektura uslublarini — Clean Architecture (qatlamlar, bog'liqlik yo'nalishi), layered, hexagonal (ports & adapters) — o'rganamiz. Bu — katta ilovani toza, test qilinadigan, texnologiyadan mustaqil qiladigan strukturadir.


Foydalanilgan rasmiy/ishonchli manbalar

  • Gamma, Helm, Johnson, Vlissides ("Gang of Four") — Design Patterns: Elements of Reusable Object-Oriented Software (1994) — 23 klassik pattern manbai.
  • Mario Casciaro, Luciano Mammino — Node.js Design Patterns (4-nashr) — pattern'larning Node.js/JS kontekstidagi zamonaviy talqini.
  • Robert C. Martin — Clean Architecture — pattern'lar va SOLID'ning arxitektura darajasidagi qo'llanilishi.
  • NestJS rasmiy hujjatlari (docs.nestjs.com) — Providers, Custom Providers (useFactory), Middleware, Guards, Interceptors, Pipes — pattern'larning framework ichidagi amaliy ko'rinishi.
  • TypeScript Handbook (typescriptlang.org) — Iterators & Generators, Decorators.

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
9.2-bob: Design Patterns (dizayn naqshlari) — Wisar