'Java 개발자를 위한 Dojo 개념'에 해당되는 글 1건

  1. 2012.05.18 Java 개발자를 위한 Dojo 개념
01.JAVA/Java2012. 5. 18. 01:19
반응형

Java 개발자를 위한 Dojo 개념

클래스 선언 및 컨텍스트 설정

Dave Draper, 웹스피어 앱 서버 관리 콘솔 개발자, IBM

요약:  Dojo는 웹 기반 애플리케이션에서 점점 더 많이 사용되고 있습니다. 개발자들은 대부분 강력한 Java™ 프로그래밍 기술을 갖고 있지만 Javascript에 대한 경험은 그다지 많지 않습니다. 개발자들은 유형이 강하게 지정된 오브젝트 지향 컴파일 언어로부터 유형이 약하게 지정된 동적 스크립팅 언어로 개념적 도약을 하기 위해 노력하고 있습니다. 이러한 혼란으로 인해 개발자들이 Dojo 클래스를 올바르게 선언하기는 어렵습니다. 이 기사에는 이러한 혼란을 정리하는 데 도움이 되는 정보가 있을 뿐만 아니라 Dojo가 컨텍스트를 설정하는 데 필요한 이유와 Dojo를 시작하는 방법이 기술되어 있습니다.

기사 게재일:  2011 년 12 월 14 일 
난이도: 중급 원문:  보기 PDF:  A4 and Letter (111KB)Get Adobe® Reader® 
페이지뷰:  1978 회 
의견:   0 (보기 | 의견 추가 - 로그인)

평균 평가 등급 0 개 총 0표 평균 평가 등급 (0 투표하기)
아티클 순위

소개

Javascript에 대한 경험이 거의 없거나 전혀 없는 상태에서 Dojo를 시작하려고 하는 Java 프로그래머라면 Dojo를 작동하게 하는 일부 개념을 이해하기 위해 노력하고 있을 가능성이 있다. 이 기사를 작성하는 현재, Dojo와 관련된 기본적인 문제는 Dojo가 여전히 초기 상태(버전 1.0이 2008년 2월에 릴리스되었을 뿐임)에 머물러 있고, 사용 가능한 문서도 다소 제한되어 있다는 점이다. 이 기사는 Java 코드와 Dojo 간의 격차를 메워서, 애플리케이션을 개발할 때 이 Dojo Toolkit을 사용하여 개발 속도를 신속하게 높일 수 있도록 도움을 준다.

Dojo Toolkit을 얻는 방법이나 이 도구를 사용하는 데 필요한 필수 명령문을 다루고 있는 자료는 많이 있기 때문에 이 기사에서는 이러한 정보를 다루지 않는다. 이 기사는 서블릿을 개발한 경험을 바탕으로 Dojo를 시작하려고 하는 웹 개발자를 대상으로 한다.

Javascript 해시

우선, Dojo 함수를 호출할 때(특히, "해시"나 Javascript 오브젝트를 사용할 때) 사용되는 구문을 이해해야 한다. 해시는 중괄호 사이에서 쉼표로 분리되는 속성 세트로 표현된다. 목록 1에 있는 간단한 예제에서는 6개의 속성(문자열, 정수형, 부울, 정의되지 않은 속성, 또 다른 해시 및 함수)으로 구성되는 해시를 선언하고 있다.


목록 1. Javascript 해시 예제
				
var myHash = {
    str_attr : "foo",
    int_attr : 7,
    bool_attr : true,
    undefined_attr : null,
    hash_attr : {},
    func_attr : function() {}
};			
                

Javascript는 유형이 느슨하게 지정되므로 각 속성이 속성의 이름에 링크된 값으로 초기화된다고 하더라도 초기 str_attr 속성이 순차적으로 정수나 부울 또는 기타 유형으로 설정될 수 있다. 해시에 있는 각 속성은 점 연산자를 사용하여 액세스하거나 설정할 수 있다(목록 2 참조).


목록 2. 해시 속성 액세스 및 설정
				
// Accessing a hash attribute...
console.log(myHash.str_attr);

// Setting a hash attribute...
myHash.str_attr = "bar";
                

myHash의 처음 네 가지 속성은 설명할 필요가 없을 것이다. 해시에는 해시 속성이 있을 수 있다는 사실은 당연하다. (이점은 프리미티브와 오브젝트를 모두 참조하는 Java 클래스와 유사하다고 생각될 수 있다.) 반드시 이해해야 하는 가장 중요한 속성은 마지막 속성이다.

함수는 오브젝트이다.

Java 코드에는 java.reflection.Method 클래스가 있지만, 본질적으로 이 클래스는 메소드에 대해 랩퍼로 작동한다. Javascript의 함수는 인수로서 다른 함수에 전달하고 참조하고 설정할 수 있는 기타 모든 것과 마찬가지로 오브젝트이다. 때로는 Java 메소드를 호출하는 과정에서 익명의 내부 클래스를 선언하듯이 함수를 호출하는 과정에서 함수를 새로 선언해야 한다.

Java 메소드와 Javascript 함수의 또 다른 중요한 차이점은 Javascript 함수는 다양한 컨텍스트에서 실행할 수 있다는 점이다. Java 프로그래밍에서는 키워드 this를 사용하여 함수가 사용된 클래스의 현재 인스턴스를 참조한다. Javascript 함수에서 사용되는 경우,this는 이 함수가 실행 중인 컨텍스트를 참조한다. 달리 지정하지 않는 한, 함수는 함수를 정의하는 클로저에서 실행된다.

간단히 말해서 클로저는 중괄호({}) 안에 포함된 모든 Javascript 코드라고 할 수 있다. Javascript 파일 안에서 선언된 함수는 this 키워드를 사용하여, 이 파일의 기본 본문에서 선언된 모든 변수를 액세스할 수 있지만, 조화를 이룰 다른 컨텍스트와 함께 함수를 제공되지 않는 한, 해시 안에서 선언된 함수에서는 this 키워드를 사용하여, 해시 안에서 선언된 변수만을 참조할 수 있다.

인클로즈된 함수가 Dojo 함수의 인수로 필요할 수도 있기 때문에 이러한 함수의 컨텍스트를 설정하는 방법을 이해하면 불필요한 디버깅을 많이 줄일 수 있다.

컨텍스트를 지정할 때 사용되는 기본적인 Dojo 함수는 dojo.hitch이다. dojo.hitch 함수를 결코 사용하지 않을 수도 있지만, 이 함수가 Dojo의 기본이 되는 함수이고 기타 여러 가지 함수가 은연 중에 이 함수를 호출하고 있다는 점을 이해해야 한다.

목록 3에는 컨텍스트 히칭의 작동 과정이 표시되어 있다(결과는 그림 1에 표시됨).

  • 변수가 글로벌 컨텍스트에서 정의되며(globalContextVariable), 또 다른 변수가 해시의 컨텍스트에서 선언된다(enclosedVariable).
  • accessGlobalContext() 함수는 globalContextVariable를 성공적으로 액세스하여 이 변수의 값을 표시한다.
  • 그러나, enclosedFunction() 함수는 로컬 변수(enclosedVariable)만을 액세스할 수 있다. (globalContextVariable의 값은 "undefined"로 표시된다는 점에 유의한다.)
  • dojo.hitch를 사용하여 enclosedFunction() 함수를 글로벌 컨텍스트로 "히치"하면 globalContextVariable 변수를 표시할 수 있다. 그러나 enclosedFunction() 함수가 실행 중인 컨텍스트에서 enclosedVariable를 선언하지 않았기 때문에 현재는 이 변수가 정의되지 않았다.

목록 3. 클로저 및 컨텍스트
				
var globalContextVariable = "foo";

function accessGlobalContext() {
    // This will successfully output "foo"...
    console.log(this.globalContextVariable);
};

var myHash = {
    enclosedVariable : "bar",
    enclosedFunction : function() {
                           // Display global context variable...
                           console.log(this.globalContextVariable);

                           // Display enclosed context variable...
                           console.log(this.enclosedVariable);
                       }
};

console.log("Calling accessGlobalContext()...");
accessGlobalContext();

console.log("Calling myHash.enclosedFunction()...");
myHash.enclosedFunction();

console.log("Switch the context using dojo.hitch...");
var switchContext = dojo.hitch(this, myHash.enclosedFunction);
switchContext();
            


그림 1. 컨텍스트 히칭의 작동 과정
컨텍스트 히칭의 작동 과정 

클래스 선언

클래스 선언 팁

  • myClass는 완전히 올바른 이름이지만, 완전한 클래스 이름 스타일(예: com.ibm.dojo.myClass)을 사용하여 이름을 선언하는 것이 좋다. 그렇다고 해서 이 클래스를 상대 경로 "./com/ibm/dojo/" 아래에 있는 파일 시스템에 배치해야 하는 것은 아니며, 이렇게 하는 것은 단지 클래스 간에 이름이 충돌할 가능성을 줄이기 위함이다.
  • 어떤 브라우저(Firefox)는 쉼표(,)를 무시고, 어떤 브라우저(Internet Explorer)는 제거하므로 마지막 속성 다음에는 쉼표가 없어야 한다. 이 규칙은 어느 위치에서나 해시 오브젝트를 선언할 때도 적용된다.

이 히칭이 중요한 이유는 Dojo 클래스를 선언하거나 자체 위젯을 작성하기 시작하면 분명해진다. Dojo의 기능 중 가장 우수한 것은dojo.connect 함수와 내장 pub/sub 모델을 사용하여 오브젝트를 서로 "연결"하는 기능이다.

클래스를 선언하려면 다음과 같은 세 가지 오브젝트가 필요하다.

  1. 클래스의 고유 이름
  2. 함수를 확장할 상위 클래스와 다중 상속을 시뮬레이션할 "혼합(mix-in)" 클래스
  3. 모든 속성과 함수를 정의하는 해시

목록 4에는 선언할 수 있는 가장 단순한 클래스가 표시되어 있고 목록 5에는 이 클래스를 인스턴스화하는 코드가 표시되어 있다.


목록 4. 기본적인 클래스 선언
				
dojo.declare(
   "myClass",
   null,
   {}
);


목록 5. 기본적인 클래스 인스턴스화
				
var myClassInstance = new myClass();

"진정한"(즉, 유용한) Dojo 클래스를 선언하고 싶으면 생성자를 이해해야 한다. Java 코드에서는 오버로드 생성자를 여러 개 선언하여 다양한 시그너처로 클래스를 인스턴스화할 수 있다. Dojo 클래스에서는 preambleconstructor 및 postscript를 선언할 수 있지만, 대부분의 클래스에서는 생성자만 선언하면 된다.

  • 생성자를 이용하면 constructor 인수가 확장된 클래스와 혼합된 클래스에 실제로 전달되기 전에 이 인수를 조작할 수 있으므로 다중 상속을 시뮬레이션하기 위해 다른 클래스를 혼합하지 않는 한, preamble을 선언할 필요는 없다.
  • postscript는 Dojo 위젯 라이프사이클 메소드를 드라이브하지만, 표준 Dojo 클래스에는 아무런 이점을 제공하지 않는다.

이들 중 어떤 것도 반드시 선언해야 하는 것은 아니지만, 해당 클래스의 인스턴스에 어떤 값을 전달하려면 최소한 constructor 함수는 선언해야 한다. 해당 클래스의 다른 인스턴스가 constructor 인수에 액세스하게 될 경우에는 선언된 속성에 이 인수를 지정해야 한다. 목록 6에는 constructor 인수 중 하나만을 클래스 속성에 지정한 후, 또 다른 메소드에서 두 인수를 모두 참조하는 클래스가 표시되어 있다.


목록 6. constructor 인수 지정
				
dojo.declare(
    "myClass",
    null,
    {
        arg1 : "",
        constructor : function(arg1, arg2) {
                          this.arg1 = arg1;
                      },
        myMethod : function() {
                       console.log(this.arg1 + "," + this.arg2);
                   }
    }
);

var myClassInstance = new myClass("foo", "bar");
myClassInstance.myMethod();
            


그림 2. constructor 인수를 지정한 결과
constructor 인수를 지정한 결과 

복합 속성 규칙

클래스 속성은 선언될 때 초기화되지만, 속성이 복합 오브젝트 유형(예: 해시 또는 배열)과 함께 초기화되는 경우, 이 속성은 Java 클래스의 public 정적 변수와 비슷해진다. 따라서 인스턴스가 속성을 업데이트할 때마다 변경된 속성이 기타 모든 인스턴스에 반영된다. 이러한 문제가 생기지 않도록 하려면 생성자에서 복합 속성을 초기화해야 하지만, 문자열, 부울 등과 같은 간단한 속성의 경우에는 반드시 이렇게 해야 할 필요는 없다.


목록 7. 글로벌 클래스 속성
				
dojo.declare(
    "myClass",
    null,
    {
        globalComplexArg : { val : "foo" },
        localComplexArg : null,
        constructor : function() {
                          this.localComplexArg = { val:"bar" };                          
                      }
    }
);

// Create instances of myClass A and B...
var A = new myClass();
var B = new myClass();

// Output A's attributes...
console.log("A's global val: " + A.globalComplexArg.val); 
console.log("A's local val: " + A.localComplexArg.val); 

// Update both of A's attributes...
A.globalComplexArg.val = "updatedFoo";
A.localComplexArg.val = "updatedBar";

// Update B's attributes...
console.log("A's global val: " + B.globalComplexArg.val);
console.log("A's local val: " + B.localComplexArg.val);
            


그림 3. 클래스 속성
클래스 속성 

메소드 오버라이드

수퍼클래스 메소드는 동일한 이름으로 속성을 선언하여 확장할 수 있다. Javascript는 예기치 않은 인수를 무시하고 누락된 인수를 모두 널로 대체하기 때문에 오버로드 개념이 없다. Java 코드에서는 오버로드된 메소드를 호출하기 위해 수퍼클래스 메소드(즉,super().methodName(arg1, arg1);)를 호출하지만, Dojo에서는 상속된 메소드(this.inherited(arguments);)를 사용한다. 목록 8에는 선언된 두 가지 클래스가 표시되어 있으며, 여기에서는 child가 parent를 확장하고 helloWorld 메소드를 확장하지만, inherited를 호출하여 parent의 함수에 액세스한다.


목록 8. Dojo에서 수퍼클래스 메소드 호출
	
dojo.declare(
    "parent",
    null,
    {
        helloWorld : function() {
                         console.log("parent says 'hello world'");
                     }
    }
);

dojo.declare(
    "child",
    parent,
    {
        helloWorld : function() {
                         this.inherited(arguments); // Call superclass method...
                         console.log("child says 'hello world'");
                     }
    }
);

var child = new child();
child.helloWorld();


그림 4. Dojo에서 수퍼클래스 메소드를 호출한 결과
Dojo에서 수퍼클래스 메소드를 호출한 결과 

메소드 컨텍스트 설정

목록 9에는 인스턴스화되는 즉시, 제공된 문자열 배열의 요소를 문자열 ArrayList에 복사하는 Java 클래스가 표시되어 있다. 목록 10에 있는 코드를 사용하여 같은 기능을 Dojo로 제공하는 것이 합리적이다. (constructor 함수에서 targetArray를 인스턴스화하면 targetArray가 글로벌화되는 것을 막을 수 있다.) 불행히도 dojo.forEach 메소드에서 선언된 함수는 함수의 본문을 참조하여 this를 정의하는 클로저를 작성하기 때문에 그림 5와 같은 오류 메시지가 표시된다.


목록 9. Java 코드에서 클래스 범위 지정 변수 액세스
	
import java.util.ArrayList;

public class MyClass
{
    // Declare an ArrayList of Strings...
    private ArrayList<String> targetArray = new ArrayList<String>();

    public MyClass(String[] sourceArray)
    {
        // Copy each element of a String[] into the ArrayList...
        for (String val: sourceArray) 
        {
            this.targetArray.add(val);
        }
    }
}


목록 10. Dojo에서 컨텍스트 누락
	
dojo.declare(
    "myClass",
    null,
    {
        targetArray: null,
        constructor: function(source) {
                         // Initialise in constructor to avoid making global
                         this.targetArray = []; 

                         // Copy each element from source into target...
                         dojo.forEach(source, 
                                    function(item) {
                                        this.targetArray[this.targetArray.length] = item;
                                    });
                     },
    }
);

// This will cause an error!
var myClass = new myClass(["item1","item2"]);


그림 5. Dojo에서 컨텍스트가 누락된 결과
Dojo에서 컨텍스트가 누락된 결과 

targetArray가 함수로 둘러싸인 컨텍스트에서 정의되어 있지 않다고 하더라도 인수를 사용하여 targetArray가 정의되어 있는 컨텍스트를 Dojo 함수에 전달할 수 있다. 따라서 이 컨텍스트에서 선언된 모든 오브젝트(함수 포함)를 this 키워드로 액세스할 수 있다. 목록 11에는 올바르게 구현된 결과가 표시되어 있다. (굵은체로 된 추가 코드에 주목한다.)


목록 11. Dojo에서 올바른 컨텍스트 설정
	
dojo.declare(
    "myClass",
    null,
    {
        targetArray: null,
        constructor: function(source) {
                         // Initialise in constructor to avoid making global
                         this.targetArray = []; 

                         // Copy each element from source into target...
                         dojo.forEach(source, 
                                    function(item) {
                                        this.targetArray[this.targetArray.length] = item;
                                    }, this);
                     },
    }
);
                

언제나 컨텍스트가 Dojo 함수 시그너처에서 동일한 인수로 전달되는 것은 아니다.

  • dojo.subscribe에서는 컨텍스트가 함수가 선언되기 에 전달된다(목록 12).
  • dojo.connect에서는 트리거 메소드가 정의되어 있는 컨텍스트와 대상 메소드가 정의되어 있는 컨텍스트를 모두 제공해야 한다. 목록 13에는 예제가 표시되어 있으며 여기에서 obj1은 methodA가 정의되어 있는 컨텍스트이고 obj2는 methodB가 정의되어 있는 컨텍스트이다. obj1에서 methodA를 호출하면 obj2에서 methodB가 호출된다.

목록 12. dojo.subscribe로 컨텍스트 설정
	
dojo.declare(
    "myClass",
    null,
    {
        subscribe : function() {
                        dojo.subscribe("publication",
                                       this, 
                                       function(pub) { 
                                           this.handlePublication(pub);
                                       });
                    },

        handlePublication : function(pub) {
                                console.log("Received: " + pub);
                            }
    }
);
                


목록 13. dojo.connect로 컨텍스트 설정
	
dojo.connect(obj1, "methodA", obj2, "methodB");

결론

더 구조화된 Java 코드 환경에 익숙해진 개발자에게는 Javascript가 결코 자연스럽지 않을 것이다. 그러나 클래스 선언 기능과 관련해서 Dojo 구현은 클라이언트 측 개발이 훨씬 더 수월해질 정도로 발전했다. 컨텍스트 자체와 컨텍스트를 설정하는 시점 및 방법을 잘 이해하면 Java 개발자들이 겪는 어려움을 많이 줄일 수 있을 뿐만 아니라 그들이 자신 있게 자신의 도구 상자에 Javascript를 추가하게 될 수 있을 것이다.


참고자료

  • 시작하는 데 필요한 모든 정보와 자료는 DojoToolkit.org에서 찾을 수 있다.

  • Meet the JavaScript Development Toolkit(developerWorks, May 2008) developerWorks 기사에서 Javascript를 작성하는 데 도움이 되는 Eclipse 기반 도구에 관해 자세히 알아보자.

  • 기술 서점에서 다양한 기술 주제와 관련된 서적을 살펴보자. 

  • 기타 Ajax 기술(Dojo 포함)에 관한 자세한 정보는 developerWorks Ajax 자원 센터에서 확인할 수 있다.

  • Dojo API의 완전한 참조를 얻을 수 있다. 

  • 우수한 Dojo 코딩 예제는 Dojo campus에서 이용할 수 있다.

필자소개

Dave Draper

Dave Draper는 6년 동안 WebSphere Application Server Administrative Console을 개발해 왔다. 그는 Sun에서 인증한 웹 컴포넌트 개발자로, 웹 기반 도구를 개발하는 데 폭넓은 경험을 갖고 있다.

Posted by 1010