Skip to main content
HomeBlogsContactLinks
RSS

Prototype Pattern - Cloning Bookings Instead of Recreating Them

25 Apr 2026

  • Tech
  • Learning
  • Design Pattern
  • Engineering

Table of contents

  • Prerequisites
  • Introduction
  • What is Prototype Pattern
  • Problem in Booking System
  • Solution
  • Implementation
  • Real Usage
  • Pros and Cons
  • When not to use it
  • Conclusion
  • Reference

Prerequisites

  • Basic understanding of OOP concepts
  • Basic understanding of UML diagrams
  • Basic TypeScript knowledge

If you're not familiar with the first two points, this blog might not be suitable for you. Otherwise, you're good to go. The examples are intentionally simple and can be easily replicated in other languages.

Introduction

Hey devs, welcome back to the design pattern series! So far in our Booking System:

  • We used Builder to construct bookings step by step
  • We used Abstract Factory to create different types of bookings (Business, Holiday, etc.)
  • We used Factory Method for payment processing

Now let's solve another real problem. In our Booking System, we often encounter scenarios where users need to create bookings that are similar to ones they've made before. So, how can we create a similar booking? Copying everything from scratch is time-consuming and error-prone.

And even if we decide to copy everything manually, the object holds more than what meets the eye. A Booking isn't just a flat bag of fields. It carries nested dependencies - a TimeSlot with a Date inside it, an Insurance object with its own coverage rules, a PaymentMethod with sensitive details, and so on. When you try to copy it from the outside, you only see the surface. You grab the references - not the actual objects behind them. So your copy ends up sharing the same TimeSlot, the same Insurance, the same PaymentMethod as the original.

Mutate one, you accidentally mutate the other.

This is the classic shallow copy trap.

And it gets worse - some fields might be private. You can't even read them from the outside to copy them properly. So you end up with an incomplete clone, like the image below - the original has all its dependencies intact, but your cloned object is missing half of them.

The_Problem_Of_Copying_Objects_Prototype

Instead of creating everything from scratch... can we just reuse an existing booking? That’s where the Prototype Pattern comes in.

What is Prototype Pattern

Prototype is a creational design pattern that lets you copy existing objects without depending on their concrete classes.

Instead of creating objects from scratch, we clone an existing instance.

The_Problem_Of_Creating_It_From_Scratch_Prototype

Problem in Booking System

In our Booking System, recreating similar bookings from scratch is time-consuming and error-prone - and complex booking configurations with many add-ons, insurance options, and payment preferences make it even more tedious to set up repeatedly. On top of that, the system needs to copy objects without always knowing their specific types at runtime.

Without Prototype:

function repeatBooking(original: Booking, newTimeSlot: TimeSlot): Booking {
  return new Booking(
    original.customer,
    original.resource,
    newTimeSlot,
    original.addOns,
    original.insurance,
    original.promoCode,
    original.specialRequests,
    original.paymentMethod
  );
}

This approach is prone to errors and becomes unwieldy as we add more properties to the Booking class. If we modify the Booking class in the future, we'll need to update all the places where we manually create copies.

The_Manual_Copy_Problem_Prototype

Solution

Instead of copying manually, let the object clone itself.

Key Idea

  • Every Booking knows how to clone itself
  • Works for all booking types (Business, Holiday, etc.)
  • Supports templates and reuse naturally

The_Solution_Prototype_Pattern

Implementation

Prototype Interface

interface Prototype<T> {
  clone(): T;
}

Base Booking Class

abstract class Booking implements Prototype<Booking> {
    public customer: Customer;
    public resource: Resource;
    public timeSlot: TimeSlot;
    public addOns: string[] = [];
    public insurance?: Insurance;
    public promoCode?: string;
    public specialRequests?: string;
    public paymentMethod?: PaymentMethod;

    constructor(builder: BookingBuilder) {
        this.customer = builder.customer;
        this.resource = builder.resource;
        this.timeSlot = builder.timeSlot;
        this.addOns = builder.addOns;
        this.insurance = builder.insurance;
        this.promoCode = builder.promoCode;
        this.specialRequests = builder.specialRequests;
        this.paymentMethod = builder.paymentMethod;
    }

    abstract clone(): Booking;
}

Concrete Booking Types

class BusinessBooking extends Booking {
  clone(): Booking {
    return new BookingBuilder(
        this.customer,
        this.resource,
        this.timeSlot.clone(),
    )
    .withAddOns([...this.addOns])
    .withInsurance(this.insurance?.clone())
    .withPromoCode(this.promoCode)
    .withSpecialRequests(this.specialRequests)
    .withPaymentMethod(this.paymentMethod)
    .build();
  }
}

Supporting Classes

class TimeSlot implements Prototype<TimeSlot> {
  constructor(
    public startDate: Date,
    public durationDays: number
  ) {}

  clone(): TimeSlot {
    return new TimeSlot(
      new Date(this.startDate.getTime()),
      this.durationDays
    );
  }
}

class Insurance implements Prototype<Insurance> {
  constructor(public type: string, public coverage: number) {}

  clone(): Insurance {
    return new Insurance(this.type, this.coverage);
  }
}

class PaymentMethod implements Prototype<PaymentMethod> {
  constructor(public type: string, public details: any) {}

  clone(): PaymentMethod {
    return new PaymentMethod(
      this.type,
      JSON.parse(JSON.stringify(this.details))
    );
  }
}

Real Usage

1. Repeat Booking

class BookingService {
  repeatBooking(existing: Booking, newTimeSlot: TimeSlot): Booking {
    const cloned = existing.clone();
    cloned.timeSlot = newTimeSlot;
    return cloned;
  }
}

Think of this like "Book Again" in real apps.

2. Booking Templates (Prototype Registry)

class BookingRegistry {
  private templates: Map<string, Booking> = new Map();

  addTemplate(name: string, booking: Booking): void {
    this.templates.set(name, booking);
  }

  getTemplate(name: string): Booking | undefined {
    const template = this.templates.get(name);
    return template?.clone();
  }
}

Usage

// Build the template properly using the builder
const businessTemplate = new BookingBuilder(
  customer,
  new Room("Business Suite"),
  new TimeSlot(new Date(), 1),
)
.withAddOns(["wifi", "breakfast"])
.build();

const registry = new BookingRegistry();
registry.addTemplate("business-trip", businessTemplate);

// User selects template
const booking = registry.getTemplate("business-trip");

if (booking) {
  booking.timeSlot = new TimeSlot(new Date("2025-12-15"), 1);
  bookReservation(booking);
}

The_Booking_Flow_Prototype_Pattern

Pros and Cons

Pros

  • You can clone objects without coupling to their concrete classes
  • You can get rid of repeated initialization code in favor of cloning pre-built prototypes
  • You can produce complex objects more conveniently
  • You get an alternative to inheritance when dealing with configuration presets for complex objects
  • Reduces repetitive code when creating similar objects

Cons

  • Cloning complex objects with circular references might be challenging
  • Deep cloning complex objects can be complicated to implement correctly
  • Might require additional memory for storing prototypes

When not to use it

  • When objects have few properties or are simple to construct
  • When objects don't require initial complex setup
  • When you're dealing with objects that can't or shouldn't be copied
  • When the overhead of cloning is greater than creating from scratch And remember... use the Prototype pattern when you need a fast way to create similar objects, especially when they're complex!

Conclusion

  • Prototype Pattern = cloning objects instead of creating from scratch
  • Perfect for recurring bookings where most details stay the same
  • We saw how cloning booking templates simplifies creating similar bookings with different dates
  • The BookingRegistry provides a convenient way to manage and access commonly used templates

Ok devs, that's it for today. I tried my best to explain this pattern. In the next post, we'll explore another pattern in our Design Pattern series. If you have any queries or suggestions, please feel free to reach out to me.

Final Mental Model

  • Builder → create booking from scratch
  • Abstract Factory → create booking types
  • Prototype → reuse existing bookings

The_Mental_Model_Of_Booking_System

Code, learn, refactor, repeat

Reference

  • Prototype Pattern - by refactoring guru

Comments

Add a new comment

Stay Connected

GitHub •LinkedIn •X •Daily.dev •Email

© 2026 Chiristo. Feel free to share or reference this post with proper credit