자바스크립트 Mediator(중재자) Pattern 과 Facade Pattern 구현
Javascript 2012. 7. 4. 12:18
Mediator(중재자) Pattern
객체 설계 시 최대한 객체간의 결합도를 낮춰, 필요 시 유지보수가 용이한 형태로 설계되야 한다.
즉, 객체간의 결합도가 높아지면 높아질수록, 유지보수(수정 비용) 비용 또한 올라간다. 중재자 패턴은 이런 문제를 완하하기 위한 디자인 패턴이며, 아래 코드의 독립된 객체(user1 ~ user4)들은 자신의 상태(score)가 변경되면, 이를 중재자에게 알리고(Mediator.play()), 점수판 객체(Score)의 update 메서드를 호출해 모든 플레이어들이게 변경사항을 통지한다.
- 점수판 객체(Score)는 어떤 유저에 관한 정보도 일체 알지 못하며, 어떤 정보도 저장하지 않는다.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head id="Head1" runat="server"> <title></title> <script type="text/javascript"> //<![CDATA[ // Mediator(중재자) Pattern var Mediator = new (function () { var Mediator = function () { this.mediators = []; return this; } Mediator.fn = Mediator.prototype = { make: function (user) { if (!user) return false; this.mediators.push({ user: user }); return this; }, remove: function (user) { for (var t in this.mediators) { if (user) { if (this.mediators[t].user === user) { delete this.mediators[t]; } } else { delete this.mediators[t]; } } return this; }, play: function () { var names = [] , scores = []; for (var n in this.mediators) { names.push(this.mediators[n].user.name); scores.push(this.mediators[n].user.score); } var score = new Score(); score.update.apply(score, [names, scores]); } } return Mediator; } ())(); function Users(name) { this.name = name; this.score = 0; // 플레이어 목록 추가 Mediator.make(this); return this; } Users.prototype.play = function () { this.score++; // boardcast call Mediator.play(); return false; } function Score() { return this; } Score.prototype.update = function (names, scores) { var elem = document.getElementById('userScoreBoardList') , h = []; for (var t in names) { h.push('<li>' + names[t] + '님의 점수는 ' + scores[t] + '</li>'); } elem.innerHTML = h.join(''); return this; } window.onload = function () { user1 = new Users('user1'); user2 = new Users('user2'); user3 = new Users('user3'); user4 = new Users('user4'); //Mediator.remove(user4); } //]]> </script> </head> <body> <a href="#" onclick="return user1.play()">user1</a> <a href="#" onclick="return user2.play()">user2</a> <a href="#" onclick="return user3.play()">user3</a> <a href="#" onclick="return user4.play()">user4</a> <ul id="userScoreBoardList"></ul> </body> </html>
Facade Pattern
사용되는 빈도가 높은 메서드들을 하나로 감싸 새로운 메서드를 만들어 좀 더 편리한 API를 제공하는 디자인 패턴이다.
가장 대표적인 예로 아래와 코드에서 처럼 크로스 브라우징을 위한 DOM Event 할당 함수(addEventListener, attachEvent)를 꼽을 수 있다.
var Facade = new (function () { var Facade = function () { return this; } Facade.fn = Facade.prototype = { bind: function (elem, type, handler, capture) { type = typeof type === 'string' ? type : ''; handler = typeof handler === 'function' ? handler : function () { ; }; capture = capture || false; if (elem.addEventListener) { elem.addEventListener(type, handler, capture); } else if (elem.attachEvent) { elem.attachEvent('on' + type, handler); } return this; }, unbind: function (elem, type, handler, capture) { type = typeof type === 'string' ? type : ''; handler = typeof handler === 'function' ? handler : function () { ; }; capture = capture || false; if (elem.removeEventListener) { elem.removeEventListener(type, handler, capture); } else if (elem.detachEvent) { elem.detachEvent('on' + type, handler); } return this; } } return Facade; } ())(); window.onload = function () { var btn1 = document.getElementById('btn1'); var btn1_callback = function () { alert('btn1'); return false; }; var btn2 = document.getElementById('btn2'); var btn2_callback = function () { alert('btn2'); return false; }; Facade.bind(btn1, 'click', btn1_callback).unbind(btn1, 'click', btn1_callback); Facade.bind(btn2, 'click', btn2_callback); }