用「複製一個既有物件」來產生新物件,取代從零
new;新物件以原型為範本,呼叫端不必知道它的具體類別,也省去昂貴的重新初始化。
🧠 When to Use
TIP
訊號:建立一個物件很貴(要查 DB、讀檔、複雜計算),但你手上已經有一個「長得差不多」的實例,複製它再微調,比重新組裝快得多。
- 物件初始化成本高,而既有實例可當範本直接複製。
- 想避免與具體類別耦合——拿到一個 prototype 就能
clone(),不必知道它是誰。 - 需要大量結構相近、只差少數欄位的物件(如編輯器裡複製貼上的圖形)。
⚖️ Structure & Variants
經典版 — clone() 自我複製
interface Shape { fun clone(): Shape }
data class Circle(var x: Int, var y: Int, val style: Style) : Shape {
override fun clone() = copy(style = style.copy()) // 連同可變的 style 一起複製
}
val original = Circle(0, 0, Style(color = "red"))
val pasted = original.clone().also { it.x = 100 } // 以原型為範本,再微調- 複製邏輯封裝在物件自己身上;呼叫端只認
Shape介面,不碰具體型別。
深拷貝 vs 淺拷貝陷阱
- 淺拷貝:只複製欄位的引用,巢狀的可變物件仍共用同一份——改 copy 會連帶改到 original。
- 深拷貝:連同內部物件遞迴複製,彼此獨立,但成本高、遇到循環引用要小心。
- Kotlin 的
data class.copy()是淺拷貝:可變的巢狀欄位要自己再copy()(如上例的style)。
與 Builder / Factory Method 的差別
- Prototype:不從零組,複製既有物件當起點。
- Builder:一步步組裝全新物件。
- Factory Method:靠子類別決定
new哪個型別;prototype 則用實例本身決定。
⚠️ Misuse & Anti-patterns
- 淺拷貝當深拷貝用:以為
clone()出來是獨立物件,結果共用了內部可變狀態,改一個動到另一個——最常見的暗坑。 - 複製比重建還貴:物件其實很輕,硬要維護 prototype 與 clone 機制只是增加複雜度,直接
new更快更清楚。 - clone 漏掉新欄位:手寫複製邏輯後又加了欄位卻忘了一起複製,產生靜默的狀態遺失;能用語言內建
copy就別手刻。
🔑 Takeaways
- 解決的是「昂貴建立 + 已有相似範本」:複製既有物件取代從零
new。 - 成立關鍵在拷貝深淺:巢狀可變狀態沒做深拷貝,就會偷偷共用、互相污染。
- 物件不貴、結構不複雜時別用;它的價值只在「重建成本」遠大於「複製成本」時才浮現。
No notes yet — jot your takeaways or Q&A here.