Strategy Pattern

Posted by Dustin Boston in .

The Strategy Pattern is a behavioral design pattern that allows the selection of algorithms at runtime by encapsulating them in separate classes, promoting flexibility and reusability.


The Strategy Pattern is a behavioral design pattern that decouples the client
from its implementation by encapsulating algorithms in separate classes. This
pattern allows the client to select and use different algorithms interchangeably at runtime, promoting flexibility and cleaner code.

Source Code Listing

code.ts

type Strategy<T> = {
  validate(value: T): boolean;
  algorithmInterface(): void;
};

// ConcreteStrategyA
export class EmailValidationStrategy implements Strategy<string> {
  validate(value: string): boolean {
    return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.exec(value) !== null;
  }

  algorithmInterface(): void {
    console.log("ConcreteStrategyA");
  }
}

// ConcreteStrategyB
export class PhoneValidationStrategy implements Strategy<string> {
  validate(value: string): boolean {
    return /^(\+?\d{1,2}[-\s]?|)(?:\d{3}[-\s]?){2}\d{4}$/.exec(value) !== null;
  }

  algorithmInterface(): void {
    console.log("ConcreteStrategyB");
  }
}

// ConcreteStrategyC
export class MonthValidationStrategy implements Strategy<string> {
  validate(value: string): boolean {
    return (
      /^(Jan|Feb|March|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)$/.exec(value) !==
      null
    );
  }

  algorithmInterface(): void {
    console.log("ConcreteStrategyC");
  }
}

export class Context {
  constructor(private readonly strategy: Strategy<string>) {}

  // ContextInterface(): void {
  //   this.strategy.algorithmInterface();
  // }

  validate(value: string): boolean {
    return this.strategy.validate(value);
  }
}

test.ts

import {describe, test, expect} from "bun:test";
import {
  Context,
  EmailValidationStrategy,
  MonthValidationStrategy,
  PhoneValidationStrategy,
} from "./code.ts";

describe("Strategy Pattern", () => {
  test("should validate email", () => {
    const context = new Context(new EmailValidationStrategy());
    const result = context.validate("no-reply@email.clutter");
    expect(result).toBe(true);
  });

  test("should validate phone", () => {
    const context = new Context(new PhoneValidationStrategy());
    const result = context.validate("123-456-7890");
    expect(result).toBe(true);
  });

  test("should validate month", () => {
    const context = new Context(new MonthValidationStrategy());
    const result = context.validate("Jan");
    expect(result).toBe(true);
  });
});