Experiment

앵버박사 2014. 6. 2. 15:50

[디자인패턴] 디자인패턴 라이팅 도전기 - 01 편 기억나시나요?? 루프를 이터레이터 함수로 분리하여 중첩 루프를 제거하는 패턴이었습니다. 이번에 JQL이라는 자바스크립트 라이브러리를 개발하면서 조금 업그레이드 하여 적용해봤습니다. 기존 중첩 루프 제거 패턴의 단점은 다음과 같습니다.


1. 이터레이터 함수에 계속해서 마지막으로 실행될 함수( lastFunction )를 전달 해주어야 한다.

2. 이터레이터 함수 끼리 변수를 공유할 수 없다.

3. 배열이 아닌 오브젝트를 반복작업 할 수 없다.( 인덱스 대신 키값을 받아야 함 )


이 단점을 없애기 위해 새롭게 도입한 Iterator클래스를 소개합니다.


function Iterator( $lastFunction ) {

     this.lastFunction = $lastFunction;

}


Iterator.prototype.foreach = function( $roof, $nextFunction, $keyFlag ) {          

     _utils.foreach( $roof, $nextFunction, this, $keyFlag );

};


인자로 마지막 실행 함수를 받아 자신의 속성으로 저장하고 있고, 이 패턴의 핵심인 기존 foreach 함수를 래핑하여 자신의 foreach함수를 만들었습니다. 이는 이터레이터 함수의 인터페이스를 단순화 하고, 변수들의 공유를 가능케 합니다.( 위 단점의 1 번과 2번 )


그리고 foreach함수는 다음과 같이 변경하였습니다.


var _utils = {

          foreach : function( $roof, $nextFunction, $excuteContext, $keyFlag ) {

               if ( $keyFlag ) {

                    for ( var key in $roof )

                         $nextFunction.apply( $excuteContext, [ key, $roof ] );

               } else {

                    for ( var i = 0; i < $roof.length; i++ )

                         $nextFunction.apply( $excuteContext, [ i, $roof ] );

               }

          }

}


이로써 단점 3번도 커버할 수 있게 되었습니다. 또한 $nextFunction에 apply로 Iterator클래스를 실행컨텍스트로 넘겨주어 this를 이용하여 변수를 공유할 수 있게 됩니다.


자~ 그럼 본격적으로 이터레이터 함수를 만들고 실행해볼 까요~

우선 시작점인 foreach문은 다음처럼 변경됩니다.


_utils.foreach( beginObject, firstIterator, new Iterator( function( $index, $parent ) {

     var item = $parent[ $index ];     

} ) );


새롭게 만든 Iterator클래스를 마지막 인자로 넘겨주었습니다.

그리고 필요한 나머지 Iterator들을 아래의 형식으로 만들어 연결하면 끝!( Psedo code 입니다. )


var firstIterator = function( $index, $parent ) {

     var nextRoof = $parent[ $index ];

     this.var01 = "var01";


     this.foreach( nextRoof, secondIterator, true );


     if ( this.var01 === "var01" )

          console.log( "var01" );

     else

          console.log( "not var01" );

};


var secondIterator = function( $key, $parent ) {

     var nextRoof = [ 1, 2, 3, 4, 5 ];     

     this.var02 = this.var01 + "var02";


     this.foreach( nextRoof, thirdIterator );


     this.var01 = "var02";

};


var thirdIterator = function( $index, $parent ) {

     this.itemList = $parent[ $index ];

     

     this.foreach( this.itemList, this.lastFunction );

};


이로써 오브젝트 루프도 할 수 있고, 이터레이터 간 공유변수도 가질 수 있으며 전처리 후처리도 가능한 패턴이 완성되었습니다.

저번 편보다 조금 더 유연하게 사용할 수 있습니다. 그러나 아무래도 성능 또는 다른부분에서 문제가 있을 것이라고 예상됩니다. 이 부분에 대해서는 추후 더 연구하여 찾아뵙도록 하겠습니다. 부족한 글 봐주셔서 감사합니다. _(_ _)_