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));