Skip to main content

🧩 Bridge × Strategy

✅ Intent of the Combination​

  • The Bridge pattern separates the notification channel (e.g., Email / Slack) from the message formatting logic (e.g., Plain / HTML), allowing both to be extended independently.
  • The Strategy pattern externalizes the message formatting behavior, enabling flexible combinations of notification channel × message style.

This design consolidates common notification behavior within Notifier, while allowing flexible injection of both the communication method and message formatting strategy.

✅ When to Use​

  • When you want to flexibly combine how a message is sent (Email, Slack, etc.) and how the message is structured (Plain text, HTML, Markdown, etc.).
  • When the system requires independent extensibility across multiple axes, such as output channels and content structure.
  • When designing systems with two or more independent concerns, such as UI vs. theme, or data vs. rendering method.

✅ UML Class Diagram​

✅ Code Example​

interface PaymentStrategy {
pay(amount: number): void;
}

class CreditCardPayment implements PaymentStrategy {
pay(amount: number): void {
console.log(`[CreditCard] Paid ${amount}`);
}
}

class PayPalPayment implements PaymentStrategy {
pay(amount: number): void {
console.log(`[PayPal] Paid ${amount}`);
}
}

interface PaymentState {
handle(amount: number): void;
setStrategy(strategy: PaymentStrategy): void;
}

class ReadyState implements PaymentState {
constructor(private strategy: PaymentStrategy) {}

handle(amount: number): void {
console.log("Ready to process payment");
this.strategy.pay(amount);
}

setStrategy(strategy: PaymentStrategy): void {
this.strategy = strategy;
}
}

class DisabledState implements PaymentState {
handle(amount: number): void {
console.log("Payment is currently disabled");
}

setStrategy(strategy: PaymentStrategy): void {
console.log("Cannot set strategy while disabled");
}
}

class PaymentContext {
constructor(private state: PaymentState) {}

setState(state: PaymentState) {
this.state = state;
}

setStrategy(strategy: PaymentStrategy) {
this.state.setStrategy(strategy);
}

pay(amount: number) {
this.state.handle(amount);
}
}

// Usage
const context = new PaymentContext(new ReadyState(new CreditCardPayment()));
context.pay(100);

context.setStrategy(new PayPalPayment());
context.pay(200);

context.setState(new DisabledState());
context.pay(300);

✅ Explanation​

  • Notifier is the abstraction that defines the notification flow. It holds a reference to a MessageStrategy to delegate message formatting (Strategy).
  • EmailNotifier and SlackNotifier are concrete implementations of notification channels (implementors in the Bridge).
  • MessageStrategy defines how a message is built. It can be swapped dynamically (e.g., PlainMessageStrategy, HtmlMessageStrategy).
  • The architecture enables independent extensibility of both how messages are sent and how they're formatted.

✅ Summary​

  • Bridge separates the concerns of how to send a message from how to build it, allowing independent extension.
  • Strategy allows the message structure to be injected and changed dynamically.
  • This combination supports high flexibility and reusability, ideal for real-world systems where content and delivery vary independently.

This architecture is especially effective in real-world applications where multiple dimensions of extensibility are required, boosting maintainability and scalability.