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.
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.
There will be two class one is creator class and another is product class where creator class will create different product based on passed data
Abstract Factory pattern
Abstract Factory is a creational design pattern that lets you create families of related objects without specifying their concrete classes.
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