JavaScriptにおけるデザインパターン１（作成系）

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

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

### 作成系デザインパターン
簡単にいうと、オブジェクト作成メカニズムを扱うデザインパターンであり、状況に即した方法でオブジェクトを作成しようとするもの。

# コンストラクターパターン

[Learning JavaScript Design Patternsより](https://addyosmani.com/resources/essentialjsdesignpatterns/book/#constructorpatternjavascript)
> コンストラクターは、メモリが割り当てられた後、新しく作成されたオブジェクトを初期化するために使用される特別なメソッドです。

```js
function Person(first, last) {
  this.first = first
  this.last = last
  this.greet = function () {
    console.log('こんにちは、' + this.last + this.first + 'です。')
  }
}

let person = new Person('太郎', '山田')
let person2 = new Person('次郎', '鈴木')

person.greet() // こんにちは、山田太郎です。
person2.greet() // こんにちは、鈴木次郎です。
```
この実装には問題があります。
他の開発者が同じソースコード内のどこかで新たな関数を追加すると下記のように変更されてしまう可能性があります。

```js
person.greet = function () {
  console.log('さようなら！')
}

person.greet() // さようなら
person2.greet() // こんにちは、鈴木次郎です。
```

同じメソッドならばどのオブジェクトに対しても同じように機能する必要があります。
そのためコンストラクター内で定義せず、コンストラクターの外で、プロトタイプというプロパティーに定義する必要があります。

```js
function Person(first, last) {
  this.first = first
  this.last = last
  //   this.greet = function () {
  //     console.log('こんにちは、' + this.last + this.first + 'です。')
  //   }
}

Person.prototype.greet = function () {
  console.log('こんにちは、' + this.last + this.first + 'です。')
}

let person = new Person('太郎', '山田')
let person2 = new Person('次郎', '鈴木')

person.greet()
person2.greet()
```


# ファクトリーパターン
[Learning JavaScript Design Patternsより](https://addyosmani.com/resources/essentialjsdesignpatterns/book/#factorypatternjavascript)
>ファクトリ パターンは、オブジェクトを作成するという概念に関係するもう 1 つの作成パターンです。カテゴリ内の他のパタ​​ーンと異なる点は、コンストラクターを使用する必要がないことです。代わりに、ファクトリはオブジェクトを作成するためのジェネリック インターフェイスを提供でき、作成するファクトリ オブジェクトのタイプを指定できます。

```js
// https://github.com/pkellz/devsage/blob/master/DesignPatterns/FactoryDesignPattern.js　より

function Developer(name)
{
  this.name = name
  this.type = "Developer"
}

function Tester(name)
{
  this.name = name
  this.type = "Tester"
}

function EmployeeFactory()
{
  this.create = (name, type) => {
    switch(type)
    {
      case 1:
        return new Developer(name)
      case 2:
        return new Tester(name)
    }
  }
}

function say()
{
  console.log("Hi, I am " + this.name + " and I am a " + this.type)
}

const employeeFactory = new EmployeeFactory()
const employees = []

employees.push(employeeFactory.create("Patrick", 1))
employees.push(employeeFactory.create("John", 2))
employees.push(employeeFactory.create("Jamie", 1))
employees.push(employeeFactory.create("Taylor", 1))
employees.push(employeeFactory.create("Tim", 2))

employees.forEach( emp => {
  say.call(emp)
})
// 結果
// Hi, I am Patrick and I am a Developer
// Hi, I am John and I am a Tester
// Hi, I am Jamie and I am a Developer
// Hi, I am Taylor and I am a Developer
// Hi, I am Tim and I am a Tester
```

このようにname、typeの違う複数のobjectを作成し利用する場合に、
`employeeFactory.create(name, type)`の一行を追加するだけで新たに追加できます。


# シングルトンパターン

[Learning JavaScript Design Patternsより](https://addyosmani.com/resources/essentialjsdesignpatterns/book/#singletonpatternjavascript)
> シングルトン パターンは、クラスのインスタンス化を単一のオブジェクトに制限する。

```js
let instance = null
function Person(first, last) {
  if (!instance) {
    this.first = first
    this.last = last
    instance = this
  } else {
    return instance
  }
}

let person = new Person('太郎', '山田')
let person2 = new Person('次郎', '鈴木')

console.log('person: ', person) // person:  Person { first: '太郎', last: '山田' }
console.log('person2: ', person2) // person2:  Person { first: '太郎', last: '山田' }

```

この例では2回目以降のnewが`else {return instance}`により新たなインスタンスが作成されないように制御しています。

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

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