to rember the design pattern narrate it as real life story

resources https://youtu.be/taj_inLi-pY?si=2qu_7nqx6YRwX0Co

1. Command Pattern: This pattern encapsulates a request as a standalone object, separating the request’s trigger from its content. This decoupling allows for flexibility in how the request is handled. In the supermarket scenario, a mother’s grocery request is written on a note (the command object), which is delivered by her daughter (the invoker) to the son who does the shopping (the receiver).

2. Observer Pattern: This pattern establishes a one-to-many relationship where multiple observers are interested in the state of a single subject. Observers register their interest with the subject and receive notifications upon state changes. At the supermarket, customers waiting for coffee (observers) register their contact information with an employee (subject) to be notified when the coffee is restocked.

3. Adapter Pattern: This pattern bridges the gap between incompatible interfaces. It converts the interface of a service to match the client’s expectations. When a shopper needs to read a product label in Spanish but only understands English, a translation app acts as an adapter, converting the Spanish text to English.

4. Factory Method Pattern: This pattern defines a method for creating objects but defers the actual object creation to subclasses. This allows for the creation of different subtypes of an object based on the specific subclass used. Different bakeries (subclasses) within and outside the supermarket provide different types of bread (subtypes) based on the same basic request for “bread”.

5. Template Method Pattern: This pattern defines a template or skeleton for an algorithm in a superclass, allowing subclasses to implement specific steps while maintaining a consistent overall structure. A baker uses a template method to make sandwiches, with specific ingredients (subclass implementations) varying between a chicken and a vegetable sandwich while the basic steps of sandwich assembly remain consistent.

6. Facade Pattern: This pattern provides a simplified interface to a complex subsystem, hiding the underlying complexity from the client. A mother asking her sons to put away groceries uses a facade pattern, as the sons handle the complexity of sorting and storing groceries in different locations without the mother needing to specify those details.

Crational Design pattern

Once upon a time in the colorful land of Toyland, there were magical creatures known as Creators. Each Creator had a unique way of bringing toys to life, showcasing various creational design patterns.

  1. Abstract Factory Pattern: The Artisan Workshop

    In the heart of Toyland, there was an Artisan Workshop where the master toymaker, the Abstract Artisan, crafted a variety of toys. Depending on the season – be it spring, summer, fall, or winter – the Artisan would use a specialized machine to create toys that matched the spirit of that season. The workshop could seamlessly switch between crafting delightful flower-shaped puzzles in spring to building snowflake-adorned snow globes in winter.

    Design Pattern Explanation: The Abstract Factory pattern is like the Artisan Workshop, creating toys that match the theme of each season using a specialized machine.

class SeasonalToyFactory {
    createToy() {
        throw new Error("Abstract method. Please implement in concrete subclass.");
    }
}
 
class SpringToyFactory extends SeasonalToyFactory {
    createToy() {
        return new FlowerToy();
    }
}
 
class WinterToyFactory extends SeasonalToyFactory {
    createToy() {
        return new SnowmanToy();
    }
}
 
  1. Builder Pattern: The Custom Toy Shop

    Right next to the Artisan Workshop, there was a Custom Toy Shop run by a jolly toymaker, the Builder Elf. Children from Toyland could visit the shop and choose the parts they wanted for their custom toy – selecting the type of body, color, and accessories. The Builder Elf would then assemble the chosen parts, creating a unique toy tailored to each child’s preferences.

    Design Pattern Explanation: The Builder pattern is like the Custom Toy Shop, where a toymaker assembles a toy based on the specific choices made by the children.

class CustomToyBuilder {
    constructor() {
        this.toy = new Toy();
    }
 
    buildBody(body) {
        this.toy.setBody(body);
    }
 
    buildColor(color) {
        this.toy.setColor(color);
    }
 
    buildAccessories(accessories) {
        this.toy.setAccessories(accessories);
    }
 
    getToy() {
        return this.toy;
    }
}
 
  1. Factory Method Pattern: The Animal Wonderland Factory

    A bit further away, there was an Animal Wonderland Factory. Here, the Animal Creator designed a variety of stuffed animals, each with its own special feature. The factory had different machines, like the Bear-Maker and Bunny-Maker, each specializing in creating a particular type of stuffed animal. Every day, the Animal Creator would decide which adorable animal to make and use the corresponding machine.

    Design Pattern Explanation: The Factory Method pattern is like the Animal Wonderland Factory, where different machines create various stuffed animals based on the decision of the Animal Creator.

class AnimalCreator {
    createAnimal() {
        throw new Error("Abstract method. Please implement in concrete subclass.");
    }
}
 
class BearCreator extends AnimalCreator {
    createAnimal() {
        return new Bear();
    }
}
 
class BunnyCreator extends AnimalCreator {
    createAnimal() {
        return new Bunny();
    }
}
 
  1. Singleton Pattern: The Timeless Toy Museum

    In the center of Toyland stood the Timeless Toy Museum, housing the most beloved and classic toys. The museum had a magical guardian, the Singleton Guardian, who ensured there was only one entrance to the museum. No matter how many children wanted to enter, they all had to go through the same door, preserving the uniqueness and timelessness of the exhibited toys.

    Design Pattern Explanation: The Singleton pattern is like the Timeless Toy Museum, where the Singleton Guardian ensures there’s only one entrance, maintaining the uniqueness and timelessness of the exhibited toys.

class SingletonGuardian {
    static #instance;
 
    constructor() {
        if (!SingletonGuardian.#instance) {
            SingletonGuardian.#instance = this;
        }
 
        return SingletonGuardian.#instance;
    }
}
 
  1. Prototype Pattern: The Replicator’s Workshop

    Nestled on the outskirts of Toyland, there was the Replicator’s Workshop. Here, the Prototype Puppeteer, a wizard with a magical wand, had the ability to duplicate toys effortlessly. When a special toy was created, the Puppeteer would wave their wand, and presto – an exact replica would appear! This allowed for the mass production of popular toys without starting from scratch each time.

    Design Pattern Explanation: The Prototype pattern is like the Replicator’s Workshop, where the Prototype Puppeteer magically duplicates toys, making exact copies without crafting each one from the beginning.

class Toy {
    clone() {
        return Object.assign(Object.create(Object.getPrototypeOf(this)), this);
    }
}
 
class PrototypePuppeteer {
    makeDuplicate(originalToy) {
        return originalToy.clone();
    }
}
 

Structural Design Patterns:

In the charming town of Toyland, where toys came to life, there was an ingenious architect named StructureBuilder. StructureBuilder loved designing magical playhouses using various structural design patterns, each contributing to the uniqueness and durability of the toy structures.

  1. Adapter Pattern: The Magical Toy Connector

    One day, the StructureBuilder wanted to connect a set of new magnetic building blocks with the existing wooden ones. To make them work together seamlessly, the architect created a Magical Toy Connector. This connector translated the language of magnets into the language of wooden pegs, allowing different types of building blocks to connect effortlessly.

    class WoodenBlock {
        insertIntoSlot() {
            // Insert into a wooden slot
        }
    }
     
    class MagneticBlock {
        attachWithMagnet() {
            // Attach with a magnet
        }
    }
     
    class MagicalToyConnector {
        connectWoodenToMagnetic(woodenBlock, magneticBlock) {
            woodenBlock.insertIntoSlot();
            magneticBlock.attachWithMagnet();
        }
    }
  2. Bridge Pattern: The Enchanted Rope Bridge

    StructureBuilder wanted to create an enchanting rope bridge connecting two treehouses. Using the Bridge pattern, the architect separated the abstraction of the bridge from its implementation. Now, whether it was a magical vine or a sparkling thread, it could be easily swapped without affecting the overall structure.

    class RopeBridge {
        constructor(implementation) {
            this.implementation = implementation;
        }
     
        crossBridge() {
            this.implementation.cross();
        }
    }
     
    class MagicalVineBridge {
        cross() {
            // Cross the bridge using magical vines
        }
    }
     
    class SparklingThreadBridge {
        cross() {
            // Cross the bridge using sparkling threads
        }
  3. Composite Pattern: The Tower of Imagination

    The StructureBuilder dreamt of creating a Tower of Imagination using a variety of building blocks. With the Composite pattern, individual blocks and complex structures could be treated uniformly. The Tower of Imagination could have both simple blocks and other towers as its components, forming a magnificent and unified structure.

    class BuildingBlock {
        build() {
            // Build the block
        }
    }
     
    class TowerOfImagination {
        constructor() {
            this.components = [];
        }
     
        addComponent(component) {
            this.components.push(component);
        }
     
        build() {
            for (const component of this.components) {
                component.build();
            }
        }
    }
  4. Decorator Pattern: The Colorful Paintbrush

    StructureBuilder wanted to add vibrant colors to a plain wooden carousel. Instead of modifying the carousel directly, the architect used the Decorator pattern. A ColorDecorator wrapped around the carousel, adding a burst of colors without altering its underlying structure.

    class Carousel {
        spin() {
            // Spin the carousel
        }
    }
     
    class ColorDecorator {
        constructor(carousel, color) {
            this.carousel = carousel;
            this.color = color;
        }
     
        spin() {
            this.carousel.spin();
            this.addColor();
        }
     
        addColor() {
            // Add the chosen color to the carousel
        }
    }
  5. Proxy Pattern The proxy pattern provides a surrogate or placeholder for another object to control access to it. For instance, managing access to an object that is expensive to instantiate.

class AuthProxy {
  constructor(user, service) {
      this.user = user;
      this.service = service;
  }

  performAction() {
      if (this.user.hasAccess) {
          this.service.performAction();
      } else {
          console.log("Access denied: You do not have permission to perform this action.");
      }
  }
}
const user = { name: "John", hasAccess: false };
const realService = new RealService();
const proxy = new AuthProxy(user, realService);

proxy.performAction();
  1. Facade Pattern: The Magic Toy Workshop

    In the heart of Toyland, StructureBuilder established the Magic Toy Workshop, a place of enchantment where various toys were crafted. To simplify the complexity of the toy-making process, StructureBuilder implemented the Facade pattern. The Magic Toy Workshop acted as a facade, providing a single entry point for creating different types of toys.

    class MagicToyWorkshop {
        createTeddyBear() {
            // Create a teddy bear
        }
     
        createDoll() {
            // Create a doll
        }
     
        createToyCar() {
            // Create a toy car
        }
    }
  2. Flyweight Pattern

    The Flyweight Pattern is useful because it helps reduce memory consumption and improve performance by sharing common parts of objects across multiple instances.

    A text editor might contain millions of characters with different fonts, styles, and sizes. By using the Flyweight Pattern, the editor can share common glyphs and styles across characters, reducing memory usage.

class FontStyle {
    constructor(font, size, color) {
        this.font = font;
        this.size = size;
        this.color = color;
    }
}
class FontFactory {
    constructor() {
        this.styles = {};
    }

    getFontStyle(font, size, color) {
        const key = `${font}-${size}-${color}`;
        if (!this.styles[key]) {
            this.styles[key] = new FontStyle(font, size, color);
        }
        return this.styles[key];
    }
}
// Client code
const factory = new FontFactory();

const style1 = factory.getFontStyle('Arial', 12, 'Black');
const style2 = factory.getFontStyle('Arial', 12, 'Black');  // Reused

console.log(style1 === style2);

Factory design pattern

Factory allows us to separate the creation of an object from the implementation. A factory wraps the creation of a new instance, giving us more flexibility and control in a way we do it. Inside the factory we choose to create a new instance of a class using the new operator, or leverage closures to dynamically build a stateful object literal, or even return a different object type based on a particular condition.

Benefits of Factory Function in Refactoring:

Single Point of Change: By using a factory function, you centralize the object creation process. Refactoring or extending logic requires changes in one place rather than throughout the codebase.

Simplifies Client Code: Client code that consumes the factory function remains unchanged, even as the complexity of the object creation process increases.

Encapsulation: The factory function encapsulates any additional logic (e.g., caching, default parameters, or new object types). This prevents duplication of logic in multiple places and reduces the risk of errors during refactoring.

Maintainability: As your code grows, maintaining a factory function becomes much easier than refactoring direct instantiation. With a factory function, you can introduce new features, make optimizations, or fix bugs without affecting the rest of the code.

 
// Vehicle constructor functions
class Car {
  constructor(brand, model) {
    this.vehicleType = 'Car';
    this.brand = brand;
    this.model = model;
  }
 
  drive() {
    return `Driving a ${this.brand} ${this.model} car.`;
  }
}
 
class Bike {
  constructor(brand, model) {
    this.vehicleType = 'Bike';
    this.brand = brand;
    this.model = model;
  }
 
  ride() {
    return `Riding a ${this.brand} ${this.model} bike.`;
  }
}
 
class Truck {
  constructor(brand, model) {
    this.vehicleType = 'Truck';
    this.brand = brand;
    this.model = model;
  }
 
  haul() {
    return `Hauling with a ${this.brand} ${this.model} truck.`;
  }
}
 
// Vehicle factory that creates vehicles based on type
class VehicleFactory {
  static createVehicle(type, brand, model) {
    switch (type) {
      case 'car':
        return new Car(brand, model);
      case 'bike':
        return new Bike(brand, model);
      case 'truck':
        return new Truck(brand, model);
      default:
        throw new Error('Vehicle type not supported.');
    }
  }
}
 
// Using the factory to create vehicles
const myCar = VehicleFactory.createVehicle('car', 'Tesla', 'Model 3');
console.log(myCar.drive()); // Output: Driving a Tesla Model 3 car.
 
const myBike = VehicleFactory.createVehicle('bike', 'Yamaha', 'MT-15');
console.log(myBike.ride()); // Output: Riding a Yamaha MT-15 bike.
 
const myTruck = VehicleFactory.createVehicle('truck', 'Ford', 'F-150');
console.log(myTruck.haul()); // 

The Factory Method Pattern defines an interface for creating an object, but lets subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.

Decorator Pattern

The Decorator Pattern attaches additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

// Base Component
class Coffee {
  getDescription() {
    return "Simple Coffee";
  }
 
  cost() {
    return 5.0;
  }
}
 
// Decorator: Milk
class MilkDecorator {
  constructor(coffee) {
    this.coffee = coffee;
  }
 
  getDescription() {
    return this.coffee.getDescription() + ", Milk";
  }
 
  cost() {
    return this.coffee.cost() + 1.5;
  }
}
 
// Decorator: Sugar
class SugarDecorator {
  constructor(coffee) {
    this.coffee = coffee;
  }
 
  getDescription() {
    return this.coffee.getDescription() + ", Sugar";
  }
 
  cost() {
    return this.coffee.cost() + 0.5;
  }
}
 
// Usage
let myCoffee = new Coffee();
console.log(myCoffee.getDescription(), "$" + myCoffee.cost());
 
myCoffee = new MilkDecorator(myCoffee);
myCoffee = new SugarDecorator(myCoffee);
 
console.log(myCoffee.getDescription(), "$" + myCoffee.cost());
 

Delegation is when one object hands off (or delegates) a task to another object to perform on its behalf.

Builder Pattern

The Builder Pattern helps you construct a complex object piece by piece — without creating a giant constructor with a million parameters.

Fluent Interface Recap

A Fluent Interface is a coding style where method calls are chained together like a sentence making the code easier to read.

builder.setSize("Large").addMilk().addSugar().build();

Design pattern from project

Pipeline flow from (pipecat)

Where used how the router in networking works where they have frame with type and each router will pass the frame to next one and check the type if they have type handle in there processor they handle and push to next one where they have direction also

Where they push to queue sample frame

class Frame {
 
TYPE:"LLM_CALL" -> each router will check and if they have handler for this they will else push to next one
}
 
 

class Step {
  constructor(fn) {
    this.fn = fn; // Function to apply at this step
    this.nextStep = null;
  }
 
  // Pipe to the next step and return it for chaining
  pipe(nextStep) {
    this.nextStep = nextStep;
    return nextStep;
  }
 
  // Execute the pipeline, passing data through each step
  execute(input) {
    const result = this.fn(input);
    return this.nextStep ? this.nextStep.execute(result) : result;
  }
}
 
// Example Functions:
const step1 = new Step((input) => input.trim());
const step2 = new Step((input) => input.toUpperCase());
const step3 = new Step((input) => `Processed: ${input}`);
 
// Pipe the steps
step1.pipe(step2).pipe(step3);
 
// Run the pipeline:
const result = step1.execute("   hello world   ");
console.log(result);  // Output: Processed: HELLO WORLD