---
# System prepended metadata

title: 'Ch 11: Prototype pattern & Revealing Module pattern (opinionted)'
tags: [clean code]

---

# Ch 11: Prototype pattern & Revealing Module pattern (opinionted)
###### tags: `clean code`

## Prototype 模式
> ### **`Object.create()`, `Object.assign()`**

:::info
不像 constructor function 或是 class，先建立好一個 "原型"，再由這個"原型"去做出 object 實體，Prototype pattern 是直接用一個既有 object 作為"樣板"，做出以此 object 為"樣板"的其他 object
:::

### Example

```javascript=
const myCar = {
  name: "Ford Escort",
  drive: function () {
    console.log(`Weeee. I'm driving ${this.name}!!!`);
  },
  panic: function () {
    console.log("Wait. How do you stop this thing?");
  }
};

const yourCar = Object.create(myCar);
yourCar.name = "Honda CRV"
yourCar.drive();
// Weeee. I'm driving Honda CRV!!!
```

<img src="https://i.imgur.com/jpZ1ELb.png" width=450px /> 

<br>

:::warning
實際上，這邊的 Prototype 模式可能更接近於:
- **物件擴展模式 Object extension pattern**
- 無建構函式的原型繼承 No-Constructor-Approach to prototypal inheritance

:heavy_exclamation_mark: 這是一種罕見的模式，經典 OOP 模式 (早期的 constructor function 或 ES6 後的 class) 通常較受青睞

~~(於是我擅自決定忽略 p.348 的 code )~~
:::

<br>

---

### Usage 何時使用

:::success
- 數個 object 之間具有一些相同性質，但又有不同"特徵"
- 運用 **`Object.create()`** 或 **`Object.assign`** 的"擴展機制" ，讓物件間經由繼承來"相互關聯"
:::

#### Example

麥當勞黑牛堡系列

```javascript=
const 黑牛堡 = {
    officialName: "經典安格斯黑牛堡",
    protien: "安格斯黑牛",
    veg: "番茄",
    sauce: "美乃滋",
    bread: "比較好吃的麵包"
};

// using 
const 蕈菇黑牛堡 = Object.create(黑牛堡);
蕈菇黑牛堡.officialName = "蕈菇安格斯黑牛堡";
蕈菇黑牛堡.veg = "蕈菇";

const 第戎黑牛堡 = Object.assign({}, 黑牛堡, {
    officialName: "法式第戎黑牛堡", sauce: "第戎醬"
});

```
<img src="https://i.imgur.com/65mZAg9.png" width=550px /> 

=====
<br>


降低成本，將身為"樣板" 的黑牛堡，改成使用一般麵包
```javascript=
黑牛堡.bread = "一般麵包"
console.log(蕈菇黑牛堡.bread); // 比較好吃的麵包
```
:::danger
其它 object 被使用樣板做完以後，就與樣板沒有連結了，不會同步更動共用 property
:::

如果我們希望他們仍然有連結
```javascript=
const relatedObject = Object.assign(Object.create(templateObject), otherExtendProperties)
```

i.e.改寫上方，全部黑牛堡系列都同步
```javascript=
const 黑牛堡 = {
    officialName: "經典安格斯黑牛堡",
    protien: "安格斯黑牛",
    veg: "番茄",
    sauce: "黃芥末醬",
    bread: "比較好吃的麵包"
}

const 蕈菇黑牛堡 = Object.assign(Object.create(黑牛堡), {
    officialName: "蕈菇安格斯黑牛堡", veg: "蕈菇"
});

黑牛堡.bread = "一般麵包"
console.log(蕈菇黑牛堡.bread); // 一般麵包
```

<br>

---

## Revealing Module 模式

> #### 透過 **IIFE** 與閉包，回傳 public 的 methods 和 properties

:::info
- 被用來 **『封裝』** 一些**私有**邏輯
- 僅 **『開放』** 一組**公用**的 API 
:::

```javascript=
const myRevealingModule = function () {
    
        let privateName = "Dong";
        let publicGreet  = "Hey there!";

        function privateFunction() {
            console.log( "Name:" + privateName );
        }
        
        function publicSetName( strName ) {
            privateName = strName;
        }

        function publicGetName() {
            privateFunction();
        }

        // Reveal public pointers to private functions and properties
        return {
            setName: publicSetName,
            greeting: publicGreet,
            getName: publicGetName
        };

    }();

myRevealingModule.getName(); // Name:Dong
myRevealingModule.setName( "WYT" );
myRevealingModule.getName(); // Name:WYT
```

### Usage 何時使用

:::success
- 需要在**私有**與**公共**之間劃清界線時 
- 具有特定的初始化邏輯時
:::

### But...
:::warning
- 在 **class, `#`, `private`** 存在之前，Revealing Module 模式是 "模擬" 真實 **『私有』** 的唯一簡便方法，也因此，現在它有點失寵了 : )
-  現在使用它的，通常是出於個人美學偏好
:::
