← Back to scenarios
ScenarioCatalog DB

File storage

Wrap file storage with optional compression and encryption before persistence.

Problem

A storage workflow must compose optional data-transformation layers such as compression and encryption around a base persistence component without modifying the storage contract.

Related patterns

Implementations

Decorator

TypeScriptApplication

Decorator in TypeScript

Adds logging and retry behavior to a notification sender by composing wrappers that preserve the same sending interface.

TypeScript
interface NotificationSender {
  send(recipient: string, message: string): Promise<void>;
}

class EmailSender implements NotificationSender {
  async send(recipient: string, message: string) {
    console.log(`Sending email to ${recipient}: ${message}`);
  }
}

abstract class NotificationSenderDecorator
  implements NotificationSender
{
  constructor(
    protected readonly sender: NotificationSender,
  ) {}

  send(recipient: string, message: string) {
    return this.sender.send(recipient, message);
  }
}

class LoggingSender extends NotificationSenderDecorator {
  async send(recipient: string, message: string) {
    console.log(`Starting notification for ${recipient}`);

    await super.send(recipient, message);

    console.log(`Completed notification for ${recipient}`);
  }
}

class RetryingSender extends NotificationSenderDecorator {
  async send(recipient: string, message: string) {
    try {
      await super.send(recipient, message);
    } catch (error) {
      console.warn("First attempt failed; retrying once.");
      await super.send(recipient, message);
    }
  }
}

const sender = new LoggingSender(
  new RetryingSender(new EmailSender()),
);

void sender.send("team@example.com", "Deployment completed.");

Associated technologies