JavaScriptにおけるデザインパターン２（構造系）

# デザインパターンを整理する
デザインパターンを次の3つに分けて考えます

- 作成系デザインパターン (コンストラクター、ファクトリー、シングルトンなど）
- 構造系デザインパターン (デコレータ、ファサードなど）
- 振舞い系デザインパターン (イテレータ、メディエータ、オブザーバーなど）

### 構造系デザインパターン
[Learning JavaScript Design Patternsより](https://addyosmani.com/resources/essentialjsdesignpatterns/book/)
> 構造パターンはオブジェクトの構成に関係しており、通常、異なるオブジェクト間の関係を実現する簡単な方法を識別します。それらは、システムの一部が変更されたときに、システムの構造全体が同じことをする必要がないことを保証するのに役立ちます。また、特定の目的に適合しないシステムの部分を適合するものに作り直すのにも役立ちます。

# デコレータパターン
デコレータパターンは、オブジェクトの機能を拡張するということに注目し、プロトタイプの継承に頼るのではなく、decoratorクラスのオブジェクトにラップすることで装飾します。

```js
class Goods {
  constructor(name, price, describe) {
    this.name = name
    this.price = price
    this.describe = describe
  }
  getGoods() {
    return this.name
  }
  getPrice() {
    return this.price
  }
  getdescribe() {
    return this.describe
  }
}

class Discount {
  constructor(item) {
    this.item = item
  }
  getGoods() {
    return '【半額】' + this.item.getGoods()
  }
  getPrice() {
    return this.item.getPrice() + '円 -> ' + this.item.getPrice() / 2
  }
  getdescribe() {
    return this.item.getdescribe()
  }
}

class Recommendation {
  constructor(item) {
    this.item = item
  }
  getGoods() {
    return '【オススメ】' + this.item.getGoods()
  }
  getPrice() {
    return this.item.getPrice()
  }
  getdescribe() {
    return '＊' + this.item.getdescribe() + '＊'
  }
}

class Few {
  constructor(item) {
    this.item = item
  }
  getGoods() {
    return '【残りわずか!】' + this.item.getGoods()
  }
  getPrice() {
    return this.item.getPrice()
  }
  getdescribe() {
    return this.item.getdescribe()
  }
}

function printGoods(item) {
  console.log(`商品: ${item.getGoods()}`)
  console.log(`価格: ${item.getPrice()}円`)
  console.log(`詳細: ${item.getdescribe()}`)
}

let goods = [
  new Goods('パソコン', 50000, '普通のパソコンです'),
  new Recommendation(new Goods('高機能パソコン', 100000, '処理速度が早いです')),
  new Discount(new Goods('傷ありパソコン', 50000, '傷はあるけど使えます')),
  new Recommendation(new Few(new Discount(new Goods('有名メーカーパソコン', 120000, '某メーカーのパソコンです'))))
]

for (let i = 0; i < goods.length; i++) {
  printGoods(goods[i])
  console.log('\n')
}
// 結果

// 商品: パソコン
// 価格: 50000円
// 詳細: 普通のパソコンです

// 商品: 【オススメ】高機能パソコン
// 価格: 100000円
// 詳細: ＊処理速度が早いです＊

// 商品: 【半額】傷ありパソコン
// 価格: 50000円 -> 25000円
// 詳細: 傷はあるけど使えます

// 商品: 【オススメ】【残りわずか!】【半額】有名メーカーパソコン
// 価格: 120000円 -> 60000円
// 詳細: ＊某メーカーのパソコンです＊
```

例のようにnewでクラスの付け外しをするだけで装飾することができます。

# ファサードパターン
[Learning JavaScript Design Patternsより](https://addyosmani.com/resources/essentialjsdesignpatterns/book/#facadepatternjavascript)
> ファサードは、jQuery などの JavaScript ライブラリでよく見られる構造パターンであり、実装は幅広い動作のメソッドをサポートする場合がありますが、これらのメソッドの「ファサード」または限定された抽象化のみが使用のために公開されます。

```js
function intro() {
  return {
    printIntro: function () {
      console.log('初めまして。')
    }
  }
}

function main() {
  return {
    printMain: function () {
      console.log('これはファサードの説明です。')
    }
  }
}

function end() {
  return {
    printEnd: function () {
      console.log('ご静聴ありがとうございました。')
    }
  }
}

var Speech = {
  print: function () {
    var o1 = new intro()
    var o2 = new main()
    var o3 = new end()
    o1.printIntro()
    o2.printMain()
    o3.printEnd()
  }
}

Speech.print()
// 結果
//
// 初めまして。
// これはファサードの説明です。
// ご静聴ありがとうございました。
```
例のような形に限られたことではないですが、複数の機能をまとめたSpeechのことをファサードといえます。ファサードパターンはいたる所で使われています。

## 参考文献
[Learning JavaScript Design Patterns]
(https://addyosmani.com/resources/essentialjsdesignpatterns/book/)

## 関連記事
[JavaScriptにおけるデザインパターン１（作成系）](https://qiita.com/zgoovw_/items/40cb7459bca525f3cdc2)
[JavaScriptにおけるデザインパターン３（振舞い系）](https://qiita.com/zgoovw_/items/8cafcf8ed843da3024a4)