Decorator Pattern (Design) की जानकारी
In this page:
interface Component {
operation(): ReturnType;
}
class Decorator implements Component {
constructor(private wrapped: Component) {}
operation(): ReturnType {
return this.wrapped.operation(); // plus extra behavior
}
}
Basic Decorator
एक decorator जिस component को wrap करता है उसी interface को implement करता है, original operation उस component को delegate करता है, और पहले या बाद में extra behavior जोड़ता है — caller यह नहीं बता सकता कि वह असली चीज़ के बजाय एक decorator से बात कर रहा है।
उदाहरण: Basic Decorator
interface Coffee {
cost(): number;
}
class SimpleCoffee implements Coffee {
cost() { return 5; }
}
class MilkDecorator implements Coffee {
constructor(private coffee: Coffee) {}
cost() { return this.coffee.cost() + 1; }
}
console.log(new MilkDecorator(new SimpleCoffee()).cost());
Decorators Stack करना
Decorators दूसरे decorators को wrap कर सकते हैं, तो कई independent behaviors — logging, caching, retries — को सिर्फ wrapping calls को nest करके एक object पर layer किया जा सकता है, हर layer सिर्फ उस एक को जानते हुए जिसे वह सीधे wrap करती है।
उदाहरण: Stacking Decorators
interface Coffee {
cost(): number;
}
class SimpleCoffee implements Coffee {
cost() { return 5; }
}
class MilkDecorator implements Coffee {
constructor(private coffee: Coffee) {}
cost() { return this.coffee.cost() + 1; }
}
class SugarDecorator implements Coffee {
constructor(private coffee: Coffee) {}
cost() { return this.coffee.cost() + 0.5; }
}
const order = new SugarDecorator(new MilkDecorator(new SimpleCoffee()));
console.log(order.cost());
Shared Interface
Original component और हर decorator को same interface follow करना चाहिए ताकि callers एक decorated object को exactly original की तरह treat कर सकें, call site पर किसी special-casing के बिना।
उदाहरण: Shared Interface
interface Notifier {
send(message: string): void;
}
class EmailNotifier implements Notifier {
send(message: string) { console.log("Email:", message); }
}
class SmsDecorator implements Notifier {
constructor(private wrapped: Notifier) {}
send(message: string) {
this.wrapped.send(message);
console.log("SMS:", message);
}
}
new SmsDecorator(new EmailNotifier()).send("Hello");
Decorator बनाम Inheritance
Decorator runtime पर optional behavior जोड़ने के लिए composition उपयोग करता है, जबकि inheritance compile time पर एक fixed class hierarchy bake करता है — composition आपको एक rigid subclass tree से कहीं ज़्यादा flexibility से features mix and match करने देता है।
उदाहरण: Decorator vs Inheritance
interface Coffee { cost(): number; }
class SimpleCoffee implements Coffee { cost() { return 5; } }
// Inheritance would need a fixed subclass per combination (MilkCoffee, SugarCoffee, MilkSugarCoffee...)
// Decorator composes them at runtime instead:
class MilkDecorator implements Coffee {
constructor(private coffee: Coffee) {}
cost() { return this.coffee.cost() + 1; }
}
console.log(new MilkDecorator(new SimpleCoffee()).cost());
Decorator कब उपयोग करें
Decorator optional, composable features जैसे logging, caching, authorization, formatting, और notifications के लिए एक natural fit है — कुछ भी जो आप wrapped object के अपने code को touch किए बिना जोड़ना या हटाना चाहें।
उदाहरण: When to Use Decorator
interface Handler {
handle(req: string): string;
}
class BaseHandler implements Handler {
handle(req: string) { return `Handled: ${req}`; }
}
class LoggingDecorator implements Handler {
constructor(private wrapped: Handler) {}
handle(req: string) {
console.log("Logging request:", req);
return this.wrapped.handle(req);
}
}
console.log(new LoggingDecorator(new BaseHandler()).handle("GET /"));
- Same interface implement न करना, इसलिए decorated object को original की जगह उपयोग नहीं किया जा सकता।
- Wrapped object को delegate करना भूल जाना (
this.coffee.cost()), इसलिए base behavior खो जाता है। - इस pattern को
@decoratorsyntax के साथ confuse करना, जो एक अलग feature है।
Chapter Quiz — Complete all 7 topics to unlock
0/7 topics done
Complete these topics first: