var Observer = { EVENTID : 0, listeners: {}, addEvent : function(type, hnd){ if(!this.listeners[type]) this.listeners[type] = {}; var eventId = Observer.EVENTID++; this.listeners[type][eventId] = hnd; return eventId; }, fireEvent : function(type){ var handlers = this.listeners[type], eventId, args = Array.prototype.slice.call(arguments); if(handlers.stop) return false; args.shift(); for(eventId in handlers) if(handlers.hasOwnProperty(eventId)){ if(eventId !== "stop"){ if(!handlers[eventId].stop){ handlers[eventId].apply(this, args); } } }; }, removeEvent : function(type, hnd){ if(!this.listeners[type]) return -1; var handlers = this.listeners[type], eventId = -1; if(typeof hnd === "function"){ for(eventId in handlers) if(handlers.hasOwnProperty(f)){ if(handlers[eventId] === hnd){ delete handlers[eventId]; break; } }; return !handlers[eventId]; }else{ if(handlers[hnd]) delete handlers[hnd] return !handlers[hnd]; }; }, stopEvent : function(type, hnd){ if(!this.listeners[type]) return -1; var handlers = this.listeners[type], eventId = -1; if(hnd){ if(typeof hnd === "function"){ for(eventId in handlers) if(handlers.hasOwnProperty(f)){ if(handlers[eventId] === hnd){ handlers[eventId].stop = true; } }; }else{ handlers[hnd].stop = true; } }else{ handlers.stop = true; } }, restoreEvent : function(type, hnd){ if(!this.listeners[type]) return -1; var handlers = this.listeners[type], eventId = -1; if(hnd){ if(typeof hnd === "function"){ for(eventId in handlers) if(handlers.hasOwnProperty(f)){ if(handlers[eventId] === hnd){ handlers[eventId].stop = false; } }; }else{ handlers[hnd].stop = false; } }else{ handlers.stop = false; } }, isEvent: function(type){ var ret = false; var listeners = this.listeners[type]; var listenersLength = function() { var ret = []; for (var evtId in listeners) ret.push(evtId); return ret.length; }(); var handlerLength = function() { var ret = []; for (var evtId in listeners) { var handler = listeners[evtId]; if (handler && handler.constructor === Function) { ret.push(handler); } } return ret.length; }(); if (listenersLength && handlerLength) { if (listenersLength === handlerLength) { ret = true; } } return ret; }, applyObserver : function(tclass){ for(var p in this){ if(this[p] !== arguments.callee){ tclass.prototype[p] = this[p]; } }; return true; } }; var Interface = function() { var names = {}; var _Interface = function(name, declaratives){ return new Interface(name, declaratives); } function Interface(name, declaratives) { name = name && name.constructor === String ? name : null; declaratives = declaratives && declaratives.constructor === Object ? declaratives : null; if (!name) { throw new Error('인터페이스 이름이 정의되지 않았습니다.'); } if (!declaratives) { throw new Error('인터페이스 선언부가 정의되지 않았습니다.'); } this.propertiess = {}; this.events = []; this.methods = []; if (names[name]) { throw new Error('이미 동일한 인터페이스 이름이 존재합니다.'); } names[name] = name; var hasOwnProperty = Object.hasOwnProperty; var propertiess = declaratives.propertiess && declaratives.propertiess.constructor === Object ? declaratives.propertiess : null; var events = declaratives.events && declaratives.events.constructor === Array ? declaratives.events : null; var methods = declaratives.methods && declaratives.methods.constructor === Array ? declaratives.methods : null; if (propertiess) { for (var propertiesName in propertiess) { if (hasOwnProperty.call(propertiess, propertiesName)) { var properties = propertiess[propertiesName]; if (!properties['get'] && !properties['set']) { throw new Error('인터페이스 접근자가 선언되지 않았습니다.'); } this.propertiess[propertiesName] = properties; } } } if (events) { for (var i = 0; i < events.length; i++) { var eventName = events[i]; if (!(eventName && eventName.constructor === String)) { throw new Error('인터페이스 이벤트 선언은 (String) 타입으로 선언되어야합니다.'); } this.events.push(eventName); } } if (methods) { for (var y = 0; y < methods.length; y++) { var methodName = methods[y]; if (!(methodName && methodName.constructor === String)) { throw new Error('인터페이스 메서드 선언은 (String) 타입으로 선언되어야합니다.'); } this.methods.push(methodName); } } } _Interface.ensureImplement = function(_class, _interfaces){ _class = _class || null; _interfaces = [].slice.call(arguments, 1); if (!_class) { throw new Error('구현 클래스가 정의되지 않았습니다.'); } if (!_interfaces.length) { throw new Error('인터페이스가 정의되지 않았습니다.'); } for (var i = 0; i < _interfaces.length; i++){ var _interface = _interfaces[i]; if (!(_interface instanceof Interface)){ throw new Error('인터페이스가 정의되지 않았습니다.'); } var propertiess = _interface.propertiess && _interface.propertiess.constructor === Object ? _interface.propertiess : null; var events = _interface.events && _interface.events.constructor === Array ? _interface.events : null; var methods = _interface.methods && _interface.methods.constructor === Array ? _interface.methods : null; if (propertiess){ for (var propertiesName in propertiess) { var properties = propertiess[propertiesName]; var firstFnName = propertiesName.substr(0, 1).toUpperCase(); var lastFnName = propertiesName.substr(1); if (properties['get']) { if (!_class['get' + firstFnName + lastFnName]) { throw new Error(_class.constructor + ' 구현 클래스에서 인터페이스 속성(' + 'get' + firstFnName + lastFnName + ')이 구현되지 않았습니다.'); } } if (properties['set']){ if (!_class['set' + firstFnName + lastFnName]) { throw new Error(_class.constructor + ' 구현 클래스에서 인터페이스 속성(' + 'set' + firstFnName + lastFnName + ')이 구현되지 않았습니다.'); } } } } if (events){ for (var y = 0; y < events.length; y++) { var eventName = events[y]; if (!Observer.isEvent(eventName)) { throw new Error(_class.constructor + ' 구현 클래스에서 인터페이스 이벤트(' + eventName + ')가 구현되지 않았습니다.'); } } } if (methods){ for (var z = 0; z < methods.length; z++) { var methodName = methods[z]; var method = _class[methodName]; if (!method || method.constructor !== Function) { throw new Error(_class.constructor + ' 구현 클래스에서 인터페이스 메서드(' + methodName + ')가 구현되지 않았습니다.'); } } } } return _class; } return _Interface; }(); // DB 인터페이스 var DBInterface = Interface('DBInterface', { methods: ['connect', 'disconnect'] }); // MSSQLAPI 구현 클래스 function MSSqlAPIClass(){} MSSqlAPIClass.prototype.connect = function(){ return 'connect'; } MSSqlAPIClass.prototype.disconnect = function(id){ return 'disconnect'; } // OracleAPI 구현 클래스 function OracleAPIClass(){} OracleAPIClass.prototype.connect = function(){ return 'connect'; } OracleAPIClass.prototype.disconnect = function(id){ return 'disconnect'; } // MySqlAPI 구현 클래스 function MySqlAPIClass(){} MySqlAPIClass.prototype.connect = function(){ return 'connect'; } MySqlAPIClass.prototype.disconnect = function(id){ return 'disconnect'; } // 각 구현 클래스들이 인터페이스를 충실히 구현했는지 검증한다. console.log(Interface.ensureImplement(new MySqlAPIClass(), DBInterface)); console.log(Interface.ensureImplement(new OracleAPIClass(), DBInterface)); console.log(Interface.ensureImplement(new MySqlAPIClass(), DBInterface));