Javascipt Patterns 책의 7장 “디자인 패턴” 을 요약하였습니다.
싱글톤 패턴
- 싱글톤 패턴은 특정 클래스의 객체를 한개만 유지하는 패턴이다.
-
자바스크립트에서는 이미 객체 리터럴을 이용한 객체 생성 방법이 싱글톤 패턴과 동일하다.
var obj = { myprop : "my value" }; var obj2 = { myprop : "my value" }; obj === obj2; // false obj == obj2; // false
팩토리 패턴
- 비슷한 객체를 공장에서 찍어내듯이 반복적으로 생성할 수 있게 하는 패턴
- 컴파일 시점에 구체적인 타입(클래스)을 몰라도 객체 생성이 가능하다
-
팩토리 패턴의 가장 흔한 사례는 Object() 를 이용한 객체 생성시, 주어지는 값의 타입에 따라 String, Boolean, Number 등으로 객체가 생성되는 것이다.
// 팩토리 패턴 구현 예제 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 패턴
-
객체의 내부구조가 복잡하더라도 개별 속성에 쉽게 접근하기 위한 패턴
var element; while (element = agg.next()) { // ... console.log(element); }
-
위의 agg 객체 구현방법은 아래와 같다.
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 패턴의 예제는 아래와 같다.
var sale = new Sale(100); sale = sale.decorate("fedtax"); sale = sale.decorate("quebec"); sale = sale.decorate("money"); sale.getPrice(); // $112.88
-
구현 예제는 다음과 같다.
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(); // uber 는 상속된 객체 price += price * 5 / 100; // 5% 세율 추가 return price; } }; Sale.decorators.money = { getPrice: function () { return "$" + this.uber.getPrice().toFixed(2); } };
-
위 decorators() 를 아래와 같이 구현할 수 있다.
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 (게으른 초기화) 로 어플리케이션의 부하를 줄여준다.
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 라운드 트립을 줄일 수 있는 코드다.
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 가 다른 객체에 전달하는 방식의 코딩이 가능하다.
Observer 패턴
- 클라이언트 측 자바스크립트 프로그래밍에서 널리 사용되는 패턴이다.
- subscriber / publisher 패턴이라고도 한다.
- 예) mouseover, keypress 와 같은 브라우저 이벤트
- 이 패턴의 주요 목적은 객체간의 결합도를 낮추는 것이다.