Decorator Pattern — obyektga runtime vaqtida yangi xatti-harakat qo‘shadigan structural design pattern. Decorator original obyekt bilan bir xil interface’ni saqlaydi va chaqiriqni ichki obyektga uzatishdan oldin yoki keyin qo‘shimcha ish bajaradi.
Decorator inheritance orqali ko‘plab subclass yaratmasdan funksiyalarni kombinatsiya qilishga yordam beradi.
Component
Component — client ishlatadigan umumiy interface.
Masalan:
class Storage:
def save(self, key, data):
...
Concrete component haqiqiy storage amalini bajaradi.
Decorator ham ayni interface’ni amalga oshiradi.
Concrete component
Asosiy xatti-harakatni bajaradigan obyekt.
Misollar:
- file storage;
- database repository;
- HTTP client;
- message sender;
- stream;
- renderer.
Decorator shu obyektni ichida saqlaydi.
Base decorator
Base decorator component reference’ini qabul qiladi.
class StorageDecorator(Storage):
def __init__(self, wrapped: Storage):
self.wrapped = wrapped
Default implementation chaqiriqni ichki componentga uzatadi.
Concrete decorator kerakli qo‘shimcha xatti-harakatni qo‘shadi.
Concrete decorator
Masalan, encryption decorator:
save
→ data’ni shifrlash
→ wrapped.save
Compression decorator:
save
→ data’ni siqish
→ wrapped.save
Logging decorator:
save
→ vaqtni o‘lchash
→ wrapped.save
→ log yozish
Runtime kombinatsiya
Decoratorlar bir-biriga o‘raladi.
Logging(
Encryption(
Compression(
FileStorage
)
)
)
Har qatlam bir vazifani bajaradi.
Kombinatsiya runtime’da tanlanishi mumkin.
Tartib
Decoratorlar tartibi natijaga ta’sir qiladi.
Masalan:
compress → encrypt
odatda:
encrypt → compress
dan samaraliroq, chunki encrypted data yaxshi siqilmaydi.
Logging encryptiondan oldin yoki keyin bo‘lsa logdagi ma’lumot farq qiladi.
Tartib explicit bo‘lishi kerak.
Inheritance bilan muammo
Agar funksiyalar inheritance orqali kombinatsiya qilinsa:
EncryptedStorage
CompressedStorage
LoggedStorage
EncryptedCompressedStorage
LoggedEncryptedStorage
...
subclasslar soni tez ko‘payadi.
Decorator kichik mustaqil xatti-harakatlarni erkin kombinatsiya qiladi.
Open/Closed Principle
Mavjud component kodini o‘zgartirmasdan yangi decorator qo‘shiladi.
Bu classni extension uchun ochiq, modification uchun yopiq saqlashga yordam beradi.
Biroq interface o‘zgarsa barcha decoratorlar yangilanishi kerak.
Logging decorator
Service call davomiyligi va natijasini log qiladi.
U:
- request ID;
- operation;
- duration;
- success;
- error type
ni yozishi mumkin.
Secret va personal data logga kiritilmaydi.
Retry decorator
Vaqtinchalik xatoda operationni qayta chaqiradi.
bilan boshqariladi.
Non-idempotent operationga ko‘r-ko‘rona retry duplicate side effect yaratishi mumkin.
Cache decorator
Read operation natijasini cache qiladi.
Jarayon:
- cache key yaratish;
- cache’dan qidirish;
- miss bo‘lsa wrapped service’ni chaqirish;
- natijani cache’ga yozish.
Cache invalidation va TTL alohida boshqariladi.
Authorization decorator
Chaqiriqdan oldin user permissionini tekshiradi.
Bu cross-cutting concernni asosiy business classdan ajratadi.
Lekin object-level authorization uchun operation argumentlari to‘g‘ri tekshirilishi kerak.
Metrics decorator
Call count, latency va error metriclarini yig‘adi.
Decorator label cardinality’ni nazorat qiladi.
Request ID yoki user IDni metric label sifatida ishlatish series sonini keskin oshiradi.
Decorator va Middleware
Middleware request pipeline darajasida ishlaydi.
Decorator ma’lum interface yoki obyekt chaqirig‘ini o‘raydi.
Ikki yondashuvning maqsadi o‘xshash bo‘lishi mumkin, ammo qo‘llanish nuqtasi farq qiladi.
Decorator va Proxy
Ikkalasi ham bir xil interface bilan wrapper ishlatadi.
Decoratorning niyati xatti-harakat qo‘shish va kombinatsiya qilish.
Proxy’ning niyati access, lifecycle, remote call yoki lazy loadingni boshqarish.
Decorator va Adapter
Decorator interface’ni saqlaydi.
Adapter interface’ni boshqa ko‘rinishga aylantiradi.
Agar wrapper method nomlarini o‘zgartirsa u adapterga yaqinlashadi.
Transparent decorator
Client wrapped obyekt yoki decorator ekanini bilmasdan ishlaydi.
Buning uchun decorator Component contractni to‘liq saqlashi kerak.
Agar decorator yangi public methodlar qo‘shsa client concrete type’ni bilishi kerak bo‘ladi va transparency kamayadi.
State
Decorator o‘z state’iga ega bo‘lishi mumkin.
Masalan:
Thread-safe ishlash kerak bo‘lsa shared state synchronization talab qiladi.
Test
Har decorator alohida fake component bilan test qilinadi.
Tekshiriladi:
- wrapped method chaqirildimi;
- argument o‘zgardimi;
- return saqlandimi;
- error qanday tarqaldi;
- tartib;
- side effect soni.
Bir nechta decorator kombinatsiyasi uchun integration test ham kerak.
Kamchiliklari
Ko‘p wrapper stack trace va debuggingni murakkablashtiradi.
Tartib xatosi yashirin semantik farq yaratadi.
Object identity va equality wrapped obyekt bilan mos kelmasligi mumkin.
Decorator factory
Qaysi decoratorlar qaysi tartibda qo‘llanishini markazlashtirish uchun factory yoki composition root ishlatiladi.
Masalan:
base client
→ metrics
→ retry
→ circuit breaker
→ authentication
Client bu stackni qo‘lda yig‘maydi.
Tartib bitta joyda test qilinadi.
Return qiymatni saqlash
Decorator wrapped method return qiymati va exception semantikasini saqlashi kerak.
Masalan, logging decorator natijani o‘zgartirib yubormaydi.
Cache decorator esa contract ruxsat bersa stale yoki serialized qiymat qaytarishi mumkin.
Bu farq documentationda aniq ko‘rsatiladi.
Async decorator
Asynchronous methodni o‘raydigan decorator await, cancellation va timeoutni to‘g‘ri uzatishi kerak.
Cancellation exceptionini oddiy xato deb retry qilish operationni bekor qilib bo‘lmas holatga olib keladi.
Context va trace metadata ham wrapped callga uzatiladi.
Konfiguratsiya ko‘rinishi
Production’da decoratorlar qaysi tartibda yig‘ilgani startup log yoki dependency graph’da ko‘rsatilishi mumkin.
Bu yashirin wrapper zanjirini tahlil qilishni osonlashtiradi.
Bog‘liq tushunchalar
Structural pattern, Component, Wrapper, Composition, Proxy, Adapter, Middleware, Open-Closed Principle, Cross-cutting concern