# Prototype

## Problem

You need to create new objects that are similar to existing, already-configured objects.
Constructing them from scratch is expensive or requires knowledge of internal state that
the client shouldn't have. You want to say "give me another one like this."

## Solution

Give objects a `clone()` method that produces a **deep copy**. The client duplicates a
prototype and then customizes the copy, without knowing the concrete class or construction details.

```
         ┌─────────────────┐
         │ DocumentTemplate │
         │ +clone()         │
         │ +title           │
         │ +sections[]      │
         └────────┬────────┘
                  │ clone()
         ┌────────▼────────┐
         │  Deep Copy       │
         │  (independent)   │
         └─────────────────┘
```

## When to Use

- Object initialization is expensive (DB queries, file parsing, network calls) and you need many similar copies.
- You want to avoid subclass proliferation just to configure variants.
- The object's internal state should be copiable without exposing its details.

## When to Avoid

- Objects are simple and cheap to construct — cloning adds complexity for no gain.
- Objects contain resources that can't be meaningfully copied (open file handles, network connections).
- A Builder or Factory can create variants more clearly.

## Pseudocode

```
class DocumentTemplate:
    fields: title, sections[], metadata{}

    method clone() -> DocumentTemplate:
        copy = new DocumentTemplate()
        copy.title = this.title
        copy.sections = deepCopy(this.sections)
        copy.metadata = deepCopy(this.metadata)
        return copy

// Usage
template = DocumentTemplate()
template.title = "Quarterly Report"
template.sections = ["Summary", "Financials", "Outlook"]
template.metadata = { author: "System", version: 1 }

q1Report = template.clone()
q1Report.title = "Q1 2025 Report"
q1Report.metadata["version"] = 2
// template is unchanged
```

## Python

```python
"""Prototype — DocumentTemplate with clone via copy.deepcopy."""

import copy


class DocumentTemplate:
    """A document template that supports deep cloning."""

    def __init__(self, title: str = "", sections: list[str] | None = None,
                 metadata: dict | None = None) -> None:
        self.title = title
        self.sections = sections or []
        self.metadata = metadata or {}

    def clone(self) -> "DocumentTemplate":
        """Produce an independent deep copy."""
        return copy.deepcopy(self)

    def __repr__(self) -> str:
        return (f"Document(title={self.title!r}, "
                f"sections={self.sections}, metadata={self.metadata})")


if __name__ == "__main__":
    # Create a prototype
    template = DocumentTemplate(
        title="Quarterly Report",
        sections=["Summary", "Financials", "Outlook"],
        metadata={"author": "System", "version": 1},
    )
    print(f"Template: {template}")

    # Clone and customize
    q1 = template.clone()
    q1.title = "Q1 2025 Report"
    q1.metadata["version"] = 2
    q1.sections.append("Appendix A")
    print(f"Q1 Clone: {q1}")

    # Original is unchanged
    print(f"Template after clone modification: {template}")

    # Clone the clone
    q2 = q1.clone()
    q2.title = "Q2 2025 Report"
    q2.metadata["version"] = 3
    print(f"Q2 Clone: {q2}")
    print(f"Q1 after Q2 clone: {q1}")

    print("--- Prototype demo complete ---")
```

## Go

```go
// prototype.go — DocumentTemplate with manual deep clone
package main

import "fmt"

// DocumentTemplate is the prototype.
type DocumentTemplate struct {
	Title    string
	Sections []string
	Metadata map[string]interface{}
}

// Clone produces a deep copy.
func (d *DocumentTemplate) Clone() *DocumentTemplate {
	// Copy sections slice
	newSections := make([]string, len(d.Sections))
	copy(newSections, d.Sections)

	// Copy metadata map
	newMeta := make(map[string]interface{}, len(d.Metadata))
	for k, v := range d.Metadata {
		newMeta[k] = v
	}

	return &DocumentTemplate{
		Title:    d.Title,
		Sections: newSections,
		Metadata: newMeta,
	}
}

func (d *DocumentTemplate) String() string {
	return fmt.Sprintf("Document(title=%q, sections=%v, metadata=%v)",
		d.Title, d.Sections, d.Metadata)
}

func main() {
	// Create prototype
	template := &DocumentTemplate{
		Title:    "Quarterly Report",
		Sections: []string{"Summary", "Financials", "Outlook"},
		Metadata: map[string]interface{}{"author": "System", "version": 1},
	}
	fmt.Println("Template:", template)

	// Clone and customize
	q1 := template.Clone()
	q1.Title = "Q1 2025 Report"
	q1.Metadata["version"] = 2
	q1.Sections = append(q1.Sections, "Appendix A")
	fmt.Println("Q1 Clone:", q1)

	// Original is unchanged
	fmt.Println("Template after clone modification:", template)

	// Clone the clone
	q2 := q1.Clone()
	q2.Title = "Q2 2025 Report"
	q2.Metadata["version"] = 3
	fmt.Println("Q2 Clone:", q2)
	fmt.Println("Q1 after Q2 clone:", q1)

	fmt.Println("--- Prototype demo complete ---")
}
```

## JavaScript

```javascript
// prototype.js — DocumentTemplate with constructor-based clone
// NOTE: Do NOT use structuredClone() here — it strips class prototype methods.

class DocumentTemplate {
  constructor(title = "", sections = [], metadata = {}) {
    this.title = title;
    this.sections = sections;
    this.metadata = metadata;
  }

  /**
   * Deep clone via constructor — preserves prototype methods.
   * structuredClone() would produce a plain object without clone().
   */
  clone() {
    return new DocumentTemplate(
      this.title,
      [...this.sections],
      { ...this.metadata },
    );
  }

  toString() {
    return `Document(title=${JSON.stringify(this.title)}, ` +
      `sections=${JSON.stringify(this.sections)}, ` +
      `metadata=${JSON.stringify(this.metadata)})`;
  }
}

// --- Demo ---

// Create prototype
const template = new DocumentTemplate(
  "Quarterly Report",
  ["Summary", "Financials", "Outlook"],
  { author: "System", version: 1 },
);
console.log("Template:", template.toString());

// Clone and customize
const q1 = template.clone();
q1.title = "Q1 2025 Report";
q1.metadata.version = 2;
q1.sections.push("Appendix A");
console.log("Q1 Clone:", q1.toString());

// Original is unchanged
console.log("Template after clone modification:", template.toString());

// Clone the clone — clone() works because we used constructor, not structuredClone
const q2 = q1.clone();
q2.title = "Q2 2025 Report";
q2.metadata.version = 3;
console.log("Q2 Clone:", q2.toString());
console.log("Q1 after Q2 clone:", q1.toString());

// Verify the clone is a proper instance with methods
console.log("q2 instanceof DocumentTemplate:", q2 instanceof DocumentTemplate);
console.log("q2.clone is a function:", typeof q2.clone === "function");

console.log("--- Prototype demo complete ---");
```

## Related Patterns

- **Abstract Factory** — abstract factory can use prototype to create products by cloning a registered prototype.
- **Builder** — builder constructs objects step-by-step; prototype clones a complete existing object.
- **Flyweight** — flyweights are often immutable and shared; prototype clones are independent mutable copies.
- **Memento** — memento captures state for restoration; prototype clone captures structure for reuse.
