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 yechimlarni — design 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
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
// 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(tashqaridannewyo'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
// 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 biladiFactory — 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
// 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
thisqaytaradi (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
// 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).
SmsAdaptertashqisendSMSni bizningyuborga 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
// 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" 14000Decorator — obyektga dinamik yangi xulq qo'shish (meros'siz — o'rab). Har decorator obyektni o'raydi, qo'shimcha mantiq beradi. Bu — TS
@Decorator7.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
// 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 bilmaydiFacade — 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
// 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).
KeshProxyhaqiqiy 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
// 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 tanlashStrategy — 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
// 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
// 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
// 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)
// 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)
// 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" qiladiDependency 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
// 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
// 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 qilmaydiPrototype — 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
// 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
// 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 yokiPapkami — 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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)
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)
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
// 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)
// 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)
// 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'oyaMisol 3 — Repository (DB abstraksiya — 2.13)
// 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)
// 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)
// 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); // + logMisol 6 — Chain of Responsibility (validatsiya — 2.11)
// 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 dataMisol 7 — Singleton (NestJS kontekst — 2.2)
// 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)
// 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)
// 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 bilmaydiMisol 10 — Pattern'lar NestJS'da (umumlashtirish)
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 framework5. To'g'ri va noto'g'ri holatlar
1) Pattern uchun pattern
oddiy muammoga 5 ta pattern (over-engineering — 2.26)
oddiy yechim kerak bo'lsa pattern (KISS)2) Klassik Singleton (DI o'rniga)
getInstance() (global holat, test qiyin — 2.2)
NestJS provider (DI singleton — 2.2, Misol 7)3) switch/if (Strategy o'rniga)
katta switch (OCP buzilishi — 9.1)
Strategy + Factory (2.9, Misol 1)4) Service'da DB to'g'ridan (Repository o'rniga)
service'da SQL/query (bog'liqlik — 2.13)
Repository (DB abstraksiya)5) God Object (anti-pattern)
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)
- Strategy: to'lov usullari (Click/Payme/Uzum — Misol 1, 2.9).
- Factory: to'lov yaratish (Misol 1, 2.3).
- Observer: to'lov hodisalari email/SMS/log (Misol 2, 2.10).
- Adapter: tashqi to'lov SDK (Misol 4, 2.5).
- Repository: tranzaksiya saqlash (Misol 3, 2.13).
- Decorator: retry/log o'rash (Misol 5, 2.6).
- Chain: validatsiya zanjiri (Misol 6, 2.11).
- Facade: to'liq to'lov jarayoni (Misol 9, 2.7).
- Singleton: logger/config (DI — Misol 7, 2.2).
- 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!