Prototype pattern provide a clone method to create a new instance with the current state.

you to duplicate a ob

When to Use

  1. Object creation involves a complex configuration
  2. Object creation involves costly operations
  3. An object’s state must be copied to maintain an exact replica (e.g., in undo/redo operations).

Components

SOLID Principle

Similar to Builder pattern: SOLID Principle

Implementation

Add a Clone method to the example of Builder pattern: Interface Polymorphism + Composition (Combined with Factory Method)

Prototype pattern can be implemented in either Product or Builder (this example), if the Prototype pattern is used in Builder, the Director in the Builder pattern often becomes unnecessary or is used less frequently.

// Abstract Builder
interface Builder {
  initProduct(): void  // ← Factory Method
  setSize(size: number): void
  setColor(color: string): void
  clone(): Builder // ← Prototype pattern
  build(): Product // ← Builder pattern
}

// Concrete Builder
class ChairBuilder implements Builder {
  private product!: Chair

  initProduct(): void {
    // The product can either be encapsulated in the factory or use DI injection.
	  //  - Encapsulation: for fixed type cohesion and simplicity
  	//  - DI: for testability and runtime flexibility
    this.product = new Chair()
  }

  setSize(size: number): void {
    this.product.size = size
  }
  setColor(color: string): void {
    this.product.color = color
  }
  
  clone(): ChairBuilder {
    // Shallow copy (deep enough for this use case)
    const copy = new ChairBuilder()
    copy.product = { ...this.product }
    return copy
  }
	
  build(): Product {
    return this.product
  }
}

// .. Skip the Product codes

// Client
const originalBuilder = new ChairBuilder()
originalBuilder.initProduct()
originalBuilder.setSize(42)
originalBuilder.setColor('Blue')

const clonedBuilder = originalBuilder.clone()
clonedBuilder.setColor('Red')

// Build products
const productA = originalBuilder.build()
const productB = clonedBuilder.build()

console.log('Product A:', productA)  // Blue
console.log('Product B:', productB)  // Red

Go version: Go Interface Polymorphism + Composition (Combined with Factory Method)

// Abstract Builder
type Builder interface {
	InitProduct()    // ← Factory Method
	SetSize(int)
	SetColor(string)
	Clone() Builder  // ← Prototype pattern
	Build() Product  // ← Builder pattern
}

// Contrete Builder
type ChairBuilder struct {
	product Product
}
func (b *ChairBuilder) InitProduct() {
	// The product can either be encapsulated in the factory or use DI injection.
	//  - Encapsulation: for fixed type cohesion and simplicity
	//  - DI: for testability and runtime flexibility
	b.product = Chair{}
}
func (b *ChairBuilder) SetSize(s int)   { b.product.Size = s }
func (b *ChairBuilder) SetSize(s int)   { b.product.Size = s }
func (b *ChairBuilder) SetColor(c string) { b.product.Color = c }
func (b *ChairBuilder) Clone() Builder {
	// Shallow copy (deep enough for this use case)
	copy := *b
	return &copy
}
func (b *ChairBuilder) Build() Product { return b.product }

// .. Skip the Product codes

// Client
func main() {
	originalBuilder := &ChairBuilder{}
  originalBuilder.InitProduct()
  originalBuilder.SetSize(42)
  originalBuilder.SetColor("Blue")

  copyBuilder := originalBuilder.Clone()
  copyBuilder.SetColor("Red")

  productA := originalBuilder.Build()
  productB := copyBuilder.Build()

	fmt.Printf("Product A: %+v\\n", productA)
	fmt.Printf("Product B: %+v\\n", productB)
}

Prototype Manager

A registry that stores named prototype instances, allowing you to request a copy of a registered prototype by key.