---
###### tags: `Design Pattern`
---
# 10/29
## 原型模式 : 淺拷貝、深拷貝
- 概述:用一個已經創建的實例作為原型,通過複製該物件來創建一個和原型物件相同的新物件。
- 原型模式包含以下角色
- 抽象原型類:規定了具體原型物件必須實現的 clone() 方法。
- 具體原型類:實現抽象原型類 clone() 方法,它是可被複製的物件。
- 訪問類:使用具體原型類中的 clone() 方法來複製新的物件。
- 看起來像 JS 的 {...物件} ?
- 接口類圖如下:

- 淺複製:創建一個新物件,新物件的屬性和原來物件完全相同,對於非基本類型屬性,扔指向原有屬性所指向的物件記憶體地址,
- 深複製:創建一個新物件,屬性中引用的其他物件也會被複製,不再指向原有物件的地址。
```typescript=
class Glass {
color: string;
length: number;
constructor(color: string, length: number) {
this.color = color;
this.length = length;
}
}
class Sheep {
age: number;
hair: string;
glass: Glass;
constructor(age: number = 0, hair: string = "", glass: Glass) {
this.age = age;
this.hair = hair;
this.glass = glass;
}
canCopy(): void {
console.log("可以複製");
}
canNotCopy(): void {
console.log("不能複製");
}
shallowCopy(): Sheep {
return new Sheep(this.age, this.hair, this.glass);
}
deepClone(): Sheep {
const serializeStr = JSON.stringify(this);
const cloneObj = JSON.parse(serializeStr) as Sheep;
cloneObj.canCopy = this.canCopy;
return cloneObj;
}
}
```
```typescript=
class test {
static mainShallow(): void {
const glass = new Glass("灰", 20);
const sheep = new Sheep(3, "", glass);
console.log(`原型: ${JSON.stringify(sheep)}`); // 原型: {"age":3,"hair":"","glass":{"color":"灰","length":20}}
const sheep_1 = sheep.shallowCopy();
const sheep_2 = sheep.shallowCopy();
const sheep_3 = sheep.shallowCopy();
console.log(`sheep_1 : ${JSON.stringify(sheep)}\n`); // sheep_1 : {"age":3,"hair":"","glass":{"color":"灰","length":20}}
sheep.age = 5;
sheep.glass.color = "白";
console.log(`原型:${JSON.stringify(sheep)}`); // 原型:{"age":5,"hair":"","glass":{"color":"白","length":20}}
console.log(`sheep_1:${JSON.stringify(sheep_1)}`); // sheep_1:{"age":3,"hair":"","glass":{"color":"白","length":20}}
console.log(`sheep_2:${JSON.stringify(sheep_2)}`); // sheep_2:{"age":3,"hair":"","glass":{"color":"白","length":20}}
const sheep2_2 = sheep_2;
console.log(`sheep == sheep3 : ${sheep == sheep_3}`); // sheep == sheep3 : false
console.log(`sheep2_2 == sheep_2: ${sheep2_2 == sheep_2}`); // sheep2_2 == sheep_2: true
}
static mainDeep(): void {
const glass = new Glass("灰色", 20);
const sheep = new Sheep(3, undefined, glass);
console.log(`原型: : ${JSON.stringify(sheep)}`);
const sheep_1 = sheep.deepClone();
const sheep_2 = sheep.deepClone();
const sheep_3 = sheep.deepClone();
console.log(`sheep_1 : ${JSON.stringify(sheep_1)}\n`);
sheep.age = 5;
sheep.glass.color = "白色";
console.log(`原型:: ${JSON.stringify(sheep)}`); // 原型:: {"age":5,"hair":"","glass":{"color":"白色","length":20}}
console.log(`sheep_2: ${JSON.stringify(sheep_2)}\n`); // sheep_2: {"age":3,"hair":"","glass":{"color":"灰色","length":20}}
sheep_2.canCopy(); // 可以複製
console.log(`${sheep_2.canNotCopy}\n`); // undefined
const sheep2_2 = sheep_2;
console.log(`sheep == sheep_3: ${sheep == sheep_3}`);
console.log(`sheep2_2 == sheep_2: ${sheep2_2 == sheep_2}`);
}
}
test.mainDeep();
```
## 建造者模式 :
### 概述
- 將一個複雜物件的構造與表示分離,使同樣的構造過程可以創建不同的表示。

- 分離了部件的構造(由 builder 來負責)和裝飾(由 Director 負責)。從而可以構造出複雜的物件。==這個模式適用於:某個物件的構建過程複雜的情況。==
- 由於實現了構建和裝配的解耦。不同的構建器,相同的裝配,也可以做不同的物件;相同的構建器,不同的裝配順序也可以做出不同的物件。
- 也就實現了構建算法、裝配算法的解耦、實現了更好的復用。
- 建造者模式可以將部件和其組裝過程分開,一步步建造一個複雜物件。
- ==用戶只需要指定複雜物件的類型==,就可以得到該物件,而無需知道其內部的具體構造細節。
- 例:用戶買一台電腦,無需關心內部零件與組裝過程
### 結構
- 抽象建造者類:這個接口規定要實現複雜物件的哪些部分的創建,並不涉及具體的部件的創建。
- 具體創建者類:實現 抽象建造者類 接口,完成複雜產品的各個部件的具體創建方法。在構造過程完成後,提供產品實例。
- 產品類:要創建複雜的物件。
- 指揮者類:調用具體的建造者來創建複雜物件的各個部分,在指揮者中不涉及產品信息,只負責保證物件個部分完整創建或按某種順序創建

:::info
- 例子:生產自行車
- 生產自行車是一個複雜的過程,它包含了車架、車座等組建的生產。而車架又有碳纖維、鋁合金等材料,車座有橡膠真皮等材質。對於自行車的生產就可以使用建造者模式。
- 這裡 bike 是產品,包含車架、車座等組件;builder 是抽象建造者,MobikeBuilder 和 OfoBuilder 是具體的建造者;Director 是指揮者

:::
- 優點:
- 建造者模式的封裝性很好
- 客戶端不必要知道產品內部組成的細節,將產品本身與產品創建過程解耦。
- 可以更加精細的控制產品的創建過程。將複雜的產品創建步驟分解在不同的方法中。
- 建造者模式很容易進行擴展。如果有新的需求,通過實現一個新的建造者類就可以完成。
- 缺點:
- 造者模式所創建的產品一班具有較多的共同點,其組成部分相似,==如果產品之間的差異性很大,則不適合建造者模式==,因此其使用範圍受到一定的限制。
:::success
- 使用場景
- 創建的物件較複雜,由多個組件構成,各組件面臨著複雜的變化,但組建之間的建造順序是穩定的。
- 創建複雜物件的算法獨立於該物件的組成,以及他們的裝配方式,及產品的構建過程和最終的表示是獨立的
:::
- 擴產:使用情境
```typescript=
class Phone {
constructor(
private _cpu: string,
private _screen: string,
private _memory: string,
private _motherboard: string
) {}
}
class Client2 {
static main(): void {
const phone: Phone = new Phone("intel", "三星螢幕", "金士頓", "華碩");
console.log(phone);
}
}
```
- 傳遞參數過多,可讀性以及使用成本很高。
- p53 跳過 ts 無法在 class 內增加 class
## 建造者模式對比 :
### 工廠方法 vs 建造者模式
- 工廠方法模式注重的事==整體物件==的創建方式;而建造者模式住的是==部件構建==的過程,意在通過一步步地精確構造創建初一個複雜物件。
- 舉個例子:如果要製造一個超人,如果使用工廠方法,直接產生出來的就是一力大無窮、會飛、內褲外穿的超人
- 而如果使建建者模式,則需要組裝手、頭、腳、軀幹等部分,然後再把內褲外穿,於是一個超人就誕生了。
### 抽象工廠模式 vs 建造者模式
- 抽象工廠模式實現對產品家族的創建,一個產品家族是這樣的一系列產品: 具有不同分類維度的產品組合,採用抽像工廠模式則是不需要關心構建過程,只需要關心產品由什麼工廠生產即可。
- 建造者模式則是要求按照指定的藍圖建構產品,它的主要目的是通過組裝零配件而產生一個新產品。
- 如果將抽象工廠模式看成汽車配件生產工廠,生產一個產品族的產品,那麼建造者模式就是一個汽車組裝工廠,通過對部件的組裝可以返回一輛完整的汽車。