๐งฉ Prototype Pattern
โ Intentโ
- Create new objects by cloning a prototype rather than instantiating from scratch
- Reuse a pre-configured object as a base and apply only the necessary differences
โ Motivationโ
- Avoid hardcoding the entire configuration of an object every time
- Instead, maintain a single source of truth and clone it for variations
โ When to Useโ
- When object creation involves expensive setup or many default values
- You need to generate many similar instances with minor differences
- You're dealing with notification templates, configuration sets, or UI components
โ Code Exampleโ
- TypeScript
- PHP
- Python
interface Cloneable<T> {
clone(): T;
}
class Notification implements Cloneable<Notification> {
constructor(
public header: string,
public footer: string,
public user: string = "",
public message: string = ""
) {}
clone(): Notification {
return new Notification(this.header, this.footer);
}
send(): void {
console.log(
`${this.header}\nๅฎๅ
: ${this.user}\nๆฌๆ: ${this.message}\n${this.footer}`
);
}
}
// ใใญใใฟใคใ็ๆ
const prototype = new Notification("ไปถๅ: ใ็ฅใใ", "-- ้็ฅใทในใใ ");
// ๅฉ็จไพ
const n1 = prototype.clone();
n1.user = "hiroshi";
n1.message = "ใใใซใกใฏ";
n1.send();
const n2 = prototype.clone();
n2.user = "satoshi";
n2.message = "ใ็ฅใใใใใใพใ";
n2.send();
<?php
class Notification {
public function __construct(
public string $header,
public string $footer,
public string $user = "",
public string $message = ""
) {}
public function clone(): Notification {
return new Notification($this->header, $this->footer);
}
public function send(): void {
echo "{$this->header}\nๅฎๅ
: {$this->user}\nๆฌๆ: {$this->message}\n{$this->footer}\n";
}
}
// ใใญใใฟใคใ็ๆ
$prototype = new Notification("ไปถๅ: ใ็ฅใใ", "-- ้็ฅใทในใใ ");
// ๅฉ็จไพ
$n1 = $prototype->clone();
$n1->user = "hiroshi";
$n1->message = "ใใใซใกใฏ";
$n1->send();
$n2 = $prototype->clone();
$n2->user = "satoshi";
$n2->message = "ใ็ฅใใใใใใพใ";
$n2->send();
import copy
class Notification:
def __init__(self, header: str, footer: str, user: str = "", message: str = ""):
self.header = header
self.footer = footer
self.user = user
self.message = message
def clone(self) -> 'Notification':
return copy.deepcopy(self)
def send(self):
print(f"{self.header}\nๅฎๅ
: {self.user}\nๆฌๆ: {self.message}\n{self.footer}")
# ใใญใใฟใคใ็ๆ
prototype = Notification("ไปถๅ: ใ็ฅใใ", "-- ้็ฅใทในใใ ")
# ๅฉ็จไพ
n1 = prototype.clone()
n1.user = "hiroshi"
n1.message = "ใใใซใกใฏ"
n1.send()
n2 = prototype.clone()
n2.user = "satoshi"
n2.message = "ใ็ฅใใใใใใพใ"
n2.send()
โ Explanationโ
This code uses the Prototype
pattern to create new Notification
objects by cloning a pre-initialized instance.
Each clone inherits all base properties and logic (e.g. headers, formatting rules), and can then be customized with user-specific content before sending.
1. Prototype Pattern Overviewโ
-
Prototype: An interface or base class that defines a cloning method
โCloneable<T>
-
ConcretePrototype: Implements the cloning logic and serves as the base for duplication
โNotification
-
Client: Clones the prototype and updates only the necessary fields before use
2. Key Classes and Responsibilitiesโ
-
Cloneable<T>
- Defines the
clone()
method - Ensures each prototype instance can be duplicated
- Defines the
-
Notification
- Implements
Cloneable
- Provides
clone()
andsend()
methods - Base template can be cloned and reused with customized content
- Implements
-
Client Code
- Creates a base prototype with fixed settings
- Clones it for each user/message and customizes as needed
3. UML Class Diagramโ
4. Benefits of the Prototype Patternโ
- Avoids duplication: Write setup logic once and reuse it through cloning
- Efficient object creation: Especially useful when instantiation is complex or resource-intensive
- Flexible extension: Add variations by modifying clones instead of subclassing
This design is ideal for building systems that need to generate multiple pre-configured objects with slight variations, such as email templates, UI components, or configuration snapshots.