[Javascript]  Javascript Pattern要約 - デザインパターン


## シングルトン·パターン

シングルトン·パターン

・シングルトンパターンは特定クラスのオブジェクトを一つだけ維持するパターンだ。
・JavaScriptでは既にオブジェクトリテラルを利用したオブジェクト生成方法がシングルトンパターンと同じである。

``` javascript
var obj = {
  myprop : "my value"
};

var obj2 = {
  myprop : "my value"
};
obj === obj2; // false
obj == obj2;  // false
```

## ファクトリー·パターン

ファクトリー·パターン

・似たオブジェクトを工場で印刷するように繰り返し生成できるパターン。
・コンパイルの時点で具体的なタイプ(クラス)がわからなくてもオブジェクト生成ができる。
・ファクトリーパターンの最も多い事例は、Object()を利用したオブジェクト生成の際、与えられる値のタイプによってString、Boolean、Numberなどでオブジェクトが生成されることである。

``` javascript
function CarMaker() {}
CarMaker.prototype.drive = function () {
  return "Vroom, I have " + this.doors + "doors";
};
CarMaker.factory = function (type) {
  var constr = type,
      newcar;

  if (typeof CarMaker[constr] !== "function") {
    throw {
      name: "Error",
      message: constr + "doesn't exist"
    };
  }

  if (typeof CarMaker[constr].prototype.drive !== "function") {
    CarMaker[constr].prototype = new CarMaker();
  }

  newcar = new CarMaker[constr]();

  return newcar;
};

CarMaker.Compact = function () {
  this.doors = 4;
};
CarMaker.Convertible = function () {
  this.doors = 2;
};
CarMaker.SUV = function () {
  this.doors = 24;
};
// --

var corolla = CarMaker.factory("Compact");
var solstice = CarMaker.factory("Convertible");
corolla.drive();  // "Vroom, I have 4 doors"
solstice.drive(); // "Vroom, I have 2 doors"
```

## Iterator·パターン

Iterator·パターン

・オブジェクトの内部構造が複雑でも個別属性に容易にアクセスするためのパターン

``` javascript
var element;
while (element = agg.next()) {
  // ...
  console.log(element);
}
```
・上記のaggオブジェクトの実装方法は以下の通りである。

``` javascript
var agg = (function () {
  var index = 0,
      data = [1, 2, 3, 4, 5],
      length = data.length;

  return {
    next : function () {
      var element;
      if (!this.hasNext()) {
        return null;
      }
      element = data[index];
      index += 1;
      return element;
    },
    hasNext : function () {
      return index < length;
    },
    rewind: function () {
      index = 0;
    },
    current: function () {
      return data[index];
    }
  };
}());
```

## Decorator ·パターン

Decorator ·パターン

・ランタイム時にオブジェクトに動的に付加機能を追加できるパターン。
・Decorator パターンの例題は以下の通りである。

``` javascript
var sale = new Sale(100);
sale = sale.decorate("fedtax");
sale = sale.decorate("quebec");
sale = sale.decorate("money");
sale.getPrice(); // $112.88
```
・実装例題は以下の通りである。

``` javascript
function Sale(price) {
  this.price = price || 100;
}
Sale.prototype.getPrice = function () {
  return this.price;
};

Sale.decorators = {};
Sale.decorators.fedtax = {
  getPrice: function () {
    var price = this.uber.getPrice();
    price += price * 5 / 100; 

    return price;
  }
};
Sale.decorators.money = {
  getPrice: function () {
    return "$" + this.uber.getPrice().toFixed(2);
  }
};
```

・上記decorators()を以下のように実装することができる。

``` javascript
Sale.prototype.decorate = function (decorators) {
  var F = function () {},
      overrides = this.constructor.decorators[decorator],
      i, newobj;
  F.prototype = this;
  newobj = new F();
  newobj.uber = F.prototype;
  for (i in overrides) {
    if (overrides.hasOwnProperty(i)) {
      newobj[i] = overrides[i];
    }
  }
  return neweobj;
};
```

## プロキシ·パターン

プロキシ·パターン

・Lazy Initialization(怠けた初期化)でアプリケーションの負荷を軽減する。

``` javascript
var $ = function (id) {
  return document.getElementById(id);
};

$("vids").onclikc = function (e) {
  var src, id;

  e = e || window.event;
  src = e.target || e.srcElement;

  if (src.nodeName !== "A") {
    return;
  }

  if (type of e.preventDefault() === "function") {
    e.preventDefault();
  }

  e.returnValue = false;
  id = src.href.split('--')[1];

  if (src.className === "play") {
    src.parentNode.innerHTMl = videos.getPlayer(id);
    return;
  }

  src.parentNode.id = "v" + id;
  videos.getInfo(id);
};
```
・上記のようにクリックイベントに対してイベントハンドリングが可能である。
・下記はProxy を利用してHTTP ラウンドトリップを減らすことができるコードである。

``` javascript
var proxy = {
    ids : [],
    delay: 50,
    timeout: null,
    callback: null,
    context: null,

    makeRequest: function (id, callback, context) {
      this.ids.push(id);

      this.callback = callback;
      this.context = context;

      if (!this.timeout) {
        this.timeout = setTimeout(function () {
          proxy.flush();
        }, this.delay);
      }
    },
    flush: function () {
      http.makeRequest(this.ids, "proxy.handler:");
      this.timeout = null;
      this.ids = [];
    },
    handler: function (data) {
      var i, max;
      if (parseInt(data.query.count, 10) === 1) {
        proxy.callback.call(proxy.context, data.query.results.Video);
        return;
      }

      for (i = 0, max = data.query.results.Video.length;
            i < max; i += 1) {
        proxy.callback.call(proxy.context, data.query.results.Video[i]);
      }
    }
};
```

・HTTP 要請が50ミリメートル以内であれば、それぞれ送るのではなく、setTimeout() を利用して要請をしばらく保留した後、一度に送る。
・そうなれば、HTTP のラウンドトリップ回数が減るため、全体的に性能が向上することができる。

## Mediator·パターン

Mediator·パターン

・オブジェクト間の影響度（結合度）が高い状態では、アプリケーションのリファクタリングが予期しない結果につながることがある。
・したがって、結合度を下げるためにオブジェクトの状態が変更されると、Mediatorに先に伝達してこれをMediatorが他のオブジェクトに伝達する方式のコーディングが可能である。

## Observer·パターン

Observer·パターン

・クライアント側の子バスクリプトプログラミングで広く使用されるパターンである。
・subscriber publisher パターンともいう。
・例）mouseover、keypressなどのブラウザイベント
・このパターンの主な目的はオブジェクト間の結合度を下げることである。