IT/Flex

제3회 Flex의 체제, Cairngorm의 아키텍쳐

craveu 2008. 3. 11. 19:03
출처 : http://2005elc.elancer.co.kr/eTimes/page/eTimes_view.html?str=c2VsdW5vPTQ4MDQ=

1. 아키텍쳐의 전체상
2006/12/22  

아키텍쳐의 전체상

 우선 먼저 Cairngorm Framework의 아키텍쳐의 전체상을 설명하도록 하겠습니다. 아래의 그림을 보도록 합시다. 이것은 Cairngorm Framework의 처리의 흐름을 나타낸 대략적인 그림입니다. 그림의 번호에 따라서 흐름을 설명하도록 하겠습니다.

그림 1 Cairngorm Framework의 아키텍쳐

  1. View(MXML)는 “버튼이 클릭된” “데이터 그리드의 선택행이 바뀌었다” 등의 이벤트 발생에 근거하여 ViewHelper의 메소드를 호출한다
  2. ViewHelper는 ValueObject를 생성하여 화면의 입력값을 설정한다
  3. ViewHelper는 Cairngorm Framework의 클래스(EventBroadcaster 클래스)를 이용하여 이벤트를 발생시킨다. 이 이벤트는 1.의 이벤트와 달리 개발자 자신이 정의한다(ex : 로그인 이벤트 등)
  4. Cairngorm Framework에서는 모든 이벤트가 Controller에 통지되도록 되어 있기 때문에 Controller에 발생한 이벤트가 통지된다.
  5. Controller는 통지된 이벤트에 대응하는 Command를 취득하고 그 Command를 실행한다
  6. Command에서는 서버 측의 서비스에 액세스하기 위해서 BusinessDelegate 메소드를 호출한다
  7. BusinessDelegate는 Cairngorm Framework의 클래스(ServiceLocator 클래스)를 이용하며 서비스가 정의된 Services로부터 서비스를 룩업한다
  8. BusinessDelegate는 취득한 서비스의 메소드(비즈니스 논리)를 호출한다
  9. 서버 측의 서비스 호출 결과가 Command까지 돌아오므로 Command는 호출에 성공했을 경우와 실패했을 경우의 핸들링을 실시하여 화면에 표시시키고 싶은 데이터를 ModelLocator로 설정한다
  10. View(MXML)는 ModelLocator를 참조하여 화면을 표시한다

 이상이 Cairngorm Framework의 처리에 대한 대략적인 흐름이 됩니다. J2EE 패턴을 알고 있는 분이라면 이제 어느 정도 알게 되었을 것으로 생각합니다. 또, Struts를 사용한 적이 있다면 「Controller는 ActionServlet, ValueObject는 ActionForm, Command는 Action에 각각 대응하는 듯하다」라고 생각하시는 분들도 있을 것으로 생각합니다. 모르는 용어들뿐이라고 생각된다면 뒤의 해설을 참조하시기 바랍니다.




2. View(MXML)
2006/12/22  

View(MXML)

 그러면 가장 먼저 View(MXML)에서 보도록 합시다. 아래의 리스트는 로그인 샘플의 View인 Login.mxml입니다. LoginViewHelper를 인스턴스화하여 Login 버튼이 클릭되었을 때 LoginViewHelper의 loginUser 메소드를 호출한다는 것을 알 수 있습니다.

 또,<mx:Form>~</mx:Form>의 아래에 있는<mx:Text>태그에서는 text 속성에 ModelLocator의 statusMessage 속성을 설정하였습니다(ModelLocator에 대해서는 이후에 설명합니다).

 statusMessage에는 로그인에 실패했을 때에 표시되는 메시지가 설정되어 있어서 로그인 실패 시에는 그 메시지가 화면에 표시됩니다. ModelLocator는, Login.mxml와는 다른 패키지에 존재하므로<mx:Script>태그 내에서 가져오기를 실시하였습니다.

 「자, 로그인에 성공했을 때 표시되는 일자는 어디에 나와있는가」라는 의문이 생길 것으로 생각되는데, 로그인에 성공했을 경우에는 화면을 천이시켜 로그인 일자를 표시합니다.

 로그인 샘플인 Index.mxmL을 보면 알 수 있는데, ViewStack 컨테이너에 의해 Login.mxml와 라벨만을 가진 VBox 컨테이너의 2개가 보관 유지되어 있어서 로그인에 성공했을 경우에는 라벨만을 가진 VBox 컨테이너로 화면을 바꾸었습니다. 이 라벨에 로그인 일자가 설정되어 화면에 표시된다는 것입니다.

리스트 1 Login.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Panel xmlns:mx="http://www.macromedia.com/2003/mxml"
           xmlns:view="org.nevis.cairngorm.samples.login.view.*"
           title="Login"
           horizontalAlign="center">

     <!-- ViewHelper의 인스턴스화 -->
     <view:LoginViewHelper id="loginViewHelper" />

     <mx:Script>
     <![CDATA[  
         <!-- ModelLocator의 가져오기 -->
         import org.nevis.cairngorm.samples.login.model.ModelLocator;

     ]]>
     </mx:Script>

     <mx:Form id="loginForm">

         <mx:FormItem label="Username: ">
             <mx:TextInput id="username" />
         </mx:FormItem>

         <mx:FormItem label="Password: ">
             <mx:TextInput id="password" />
         </mx:FormItem>

     </mx:Form>

     <!-- ModelLocator를 사용하여 화면에 데이터를 표시 -->
     <mx:Text text="{ ModelLocator.statusMessage }" marginLeft="40"
width="400" height="30" />

     <mx:ControlBar>
         <!-- 버튼이 클릭되면ViewHelper의 메소드를
호출한다 -->
         <mx:Button label="Login" click="loginViewHelper.
loginUser()" />
     </mx:ControlBar>
    
</mx:Panel>


3. ViewHelper
2006/12/22  

ViewHelper

 다음으로 ViewHelper를 봅시다. ViewHelper는 J2EE 패턴 중 하나로 View에서 화면에 관한 논리를 분리시키고 보수성을 높이는 패턴입니다. MXML에서는 <mx:Script>태그 내에 Action Script를 기술할 수 있기 때문에 무심코 여기에 화면 회전의 논리를 여러가지 써버리기 쉽지만 그러면 View와 논리가 밀접하게 관계하여 보수성이 낮아집니다.

 이 패턴을 적용함으로써 View인 MXML에는 화면 회전의 논리가 비집고 들어가지 못하여 MXML을 View의 역할에 전념할 수 있게 할 수 있습니다. 실제로 방금 전 보인 Login.mxml에는 Action Script의 논리는 전혀 들어 있지 않습니다. 대신에,화면 회전의 논리는 이 ViewHelper에서 구현하게 됩니다.

 아래의 리스트는 로그인 샘플의 ViewHelper인 LoginViewHelper입니다. Login 버튼을 클릭했을 때 호출되는 loginUser 메소드에서는 ValueObject를 생성하고 그 중에 입력값인 사용자명과 패스워드를 설정하였습니다.

 여기서 화면에서의 입력값를 취득할 때 view.XXX(XXX는 MXML ID명)라는 기술로 MXML 컴포넌트에 액세스하였습니다. 이것은 각각의 ViewHelper가 Cairngorm Framework의 ViewHelper를 계승하여 작성하기 때문에 각 ViewHelper에서는 view.XXX라는 방법으로 화면의 컴포넌트에 액세스할 수 있게 되어 있기 때문입니다.

 그 후에 Cairngorm Framework에 준비된 EventBroadcaster 클래스의 broadcastEvent 메소드를 이용하여 로그인 이벤트를 발생시켰습니다. 이 이벤트는 Flex에 준비되어 있는 이벤트가 아니라 개발자 자신이 정의합니다.

 정의라고 해도 Controller 클래스에 이벤트명을 나타내는 문자열을 클래스 변수로서 선언할 뿐입니다(Controller에 대해서는 이 후에 설명합니다). broadcastEvent 메소드의 제1 인수에는 발생시키고 싶은 이벤트명을, 제2 인수에는 ValueObject의 인스턴스를 건네줍니다.

리스트 2 LoginViewHelper.as

class org.nevis.cairngorm.samples.login.view.LoginViewHelper extends ViewHelper {

     public function loginUser() {
         // ValueObject를 생성하여 화면의 입력값를 설정
         // view.XXX(XXX는 MXML ID)로 MXML 컴포넌트에 액세스가 가능
         var loginVO : LoginVO = new LoginVO();
         loginVO.username = view.username.text;
         loginVO.password = view.password.text;

         // 로그인 이벤트를 발생시킨다
         EventBroadcaster.getInstance().broadcastEvent( DemoControl.EVENT_LOGIN,
         loginVO );
     }
}




4. ValueObject
2006/12/22  

ValueObject

 ValueObject는 J2EE 패턴 중 하나로 화면의 입력값 등을 정리하여 보관 유지해 두는 클래스입니다. J2EE 패턴에서는 TransferObject라고 합니다. 원래는 EJB의 원격 메소드 호출의 회수를 줄이고 퍼포먼스의 저하를 막는 것이 목적인 패턴입니다.

 아래의 리스트는 방금 전의 LoginViewHelper 내에서 생성된 LoginVO입니다. 로그인 화면의 항목인 사용자명과 패스워드 외에 로그인한 일자를 보관 유지하는 속성를 가지고 있습니다. toString 메소드에서는 Java와 같이 객체의 문자열 표현을 돌려주었지만 구현이 필수는 아닙니다.

 ValueObject에서 특징적인 것은 Object 클래스의 registerClass 메소드를 이용하여 Action Script의 클래스와 Java의 클래스의 매핑을 실시한다는 것입니다. 여기서 매핑을 실시해 둠으로써 클라이언트 측의 Action Script의 클래스가 자동적으로 서버 측의 Java의 클래스로 변환됩니다. 이 구조 덕분에 클라이언트 측과 서버 측의 데이터의 교환을 객체 단위로 실시할 수 있습니다. 상세한 내용에 대해서는 다음 회의 샘플 애플리케이션 작성에서 해설합니다.

 각각의 ValueObject는 Cairngorm Framework의 ValueObject 인터페이스를 구현하여 작성합니다. ValueObject 인터페이스는 아무런 메소드도 정의되어 있지 않은 인터페이스입니다. 그 때문에 이 인터페이스를 구현하여도 어떤 메소드의 구현이 강제받지는 않습니다.

마커 인터페이스

1개라도 메소드가 정의되어 있지 않은 빈 인터페이스는 「마커 인터페이스」라고 불리는 경우가 있습니다. 이것은 어떤 클래스에 그 「형태」를 구현하고 있다는 표(마커)를 달기 위해서 사용됩니다. Java 언어에서는 Serializable 인터페이스나 Cloneable 인터페이스가 이 마커 인터페이스에 해당됩니다.

리스트 3 LoginVO.as

class org.nevis.cairngorm.samples.login.vo.LoginVO implements ValueObject {

     // 이 객체의 문자열 표현을 돌려준다(구현은 필수가 아니다)
     public function toString() : String {
         var s : String = "LoginVO[username=";
         s += username;
         s += ", password=";
         s += password;
         s += ", loginDate=";
         s += loginDate;
         s += " ]";
         return s;
     }

     // Action Script의 클래스와 Java의 클래스의 매핑
     public static var registered:Boolean =
         Object.registerClass( "org.nevis.cairngorm.samples.login.vo.LoginVO",
         LoginVO );

     // 사용자명
     public var username : String;
     // 패스워드
     public var password : String;
     // 로그인 일자
     public var loginDate : Date;
}



5. Controller
2006/12/23  

Controller

 계속해서 Controller를 보도록 하겠습니다. 아래의 리스트는 로그인 샘플의 Controller인 DemoController입니다. Controller 처리의 대부분은 슈퍼 클래스인 FrontController로 실시하기 때문에 각각의 Controller로 구현할 필요가 있는 것은 이벤트명의 정의와 addCommand 메소드를 이용하여 이벤트명과 그 이벤트가 발생했을 때에 호출하는 커맨드를 등록하는 2가지뿐입니다.

 FrontController는 J2EE 패턴 중 하나로 리퀘스트의 처리를 처음에 실시하는 단일 입구를 제공합니다. 입구를 1개로 함으로써 공통되는 처리 등을 한 곳에 정리할 수 있기 때문에 재이용성이나 보수성을 향상시킬 수 있습니다.

 웹 애플리케이션에서는 서블릿으로 실시되는 경우가 많으며 Struts에서는 Action Servlet가 이 FrontController에 상당합니다. Cairngorm Framework에서는 리퀘스트를 처리하는 입구가 아니라 이벤트를 제일 처음 처리하는 입구로서 기능합니다.

리스트 4 DemoControl.as

class org.nevis.cairngorm.samples.login.control.DemoControl extends
FrontController {

     // 이벤트명과 커맨드를 등록
     public function DemoControl() {
         addCommand( DemoControl.EVENT_LOGIN, new LoginCommand() )
     }

     // 이벤트명의 정의(로그인)
     public static var EVENT_LOGIN = "login";
}

 방금 전 아키텍쳐의 전체상에 대해 이야기를 하면서 「모든 이벤트는 Controller에 통지되도록 되어 있다」고 했습니다만 이것은 도대체 어디서 정해진 것일까요. 그 대답은 FrontController 클래스에 있습니다. 아래의 리스트를 봐 주십시오.

 이것은 FrontController 클래스의 내용입니다. addCommand 메소드 내에서는 이벤트명과 커맨드의 매핑을 등록하고 그 다음으로 EventBroadcaster의 인스턴스(Singleton)에 대해서 addEventListener 메소드로 청취자를 등록합니다. 이 메소드의 제1 인수에는 이벤트명, 제2 인수에는 이벤트를 포착하는 청취자를 지정하였습니다. 이벤트명은 바뀌더라도 제2 인수로 지정하는 청취자는 항상 “this”, 즉 Controller 자신이 됩니다.

 즉, EventBroadcaster에 의해서 발생되는 모든 이벤트의 청취자가 Controller가 되어 있기 때문에 이벤트가 발생하면 우선 Controller에 통지된다는 것입니다 (밑그림 참조) .

그림 2 이벤트의 발생과 청취자의 관계
핑크색 클래스는 체제, 초록색 클래스는 개발자가 작성하는 것

리스트 5 FrontController.as(발췌)

class org.nevis.cairngorm.control.FrontController {

     public function addCommand( commandName:String, commandRef:Command ) :
  Void {
         commands[ commandName ] = commandRef;
         // 청취자를 등록(커맨드명이 바뀌어도 청취자는 항상 Controller 자신)
         EventBroadcaster.getInstance().addEventListener( commandName, this );
     }

     // 커맨드를 저장해 두는 배열
     private var commands:Array;
}




6. Command
2006/12/23  

Command

 Command는 J2EE 패턴은 아니라 GoF의 디자인 패턴 중 하나로 명령을 클래스에 캡슐화한다는 것입니다. 아래의 리스트는 로그인 샘플의 Command인 LoginCommand입니다.

 각 Command는 Cairngorm Framework의 Commnad 인터페이스와 Responder 인터페이스를 구현하여 작성합니다(Action Script 2.0에서는 Java 언어와 같이 클래스를 복수 계승하는 것이 인정되지 않지만 인터페이스를 복수 구현하는 것은 인정됩니다).

 Command 인터페이스에서는 execute 메소드가 Responder 인터페이스에서는 onResult 메소드와 onFault 메소드가 각각 정의되어 있으므로 각 Command 클래스에서는 이들 3개의 메소드를 구현할 필요가 있습니다.

 execute 메소드에서는 서버 측의 서비스 호출을 실시하기 위해서 BusinessDelegate를 생성하고 그 메소드를 호출합니다. execute 메소드의 인수인 event 오브젝트의 data 속성에는 ViewHelper로 이벤트를 발생시켰을 때에 건네준 ValueObject가 설정되어 있습니다.

 LoginViewHelper에서는 로그인 이벤트를 발생시켰을 때 LoginVO의 인스턴스를 건네주었기 때문에 data 속성을 LoginVO형에 캐스트하고 그것을 BusinessDelegate의 login 메소드의 인수에 건네주고 있습니다.

 onResult 메소드에서는 서버 측의 서비스 호출에 성공했을 경우 핸들링을 실시합니다. 여기에서는 ModelLocator의 workflowState 속성에 로그인이 끝난 상태인 상태를 설정하여 서비스 호출의 결과를 동일하게 ModelLocator의 loginDate 속성에 설정하였습니다.

 onFault 메소드에서는 반대로 서버 측의 서비스 호출에 실패한 경우의 핸들링을 실시합니다. 여기에서는 ModelLocator의 statusMessage 속성에 로그인 에러의 메세지를 설정하였습니다.

리스트 6 LoginCommand.as

class org.nevis.cairngorm.samples.login.commands.LoginCommand
     implements Command, Responder {

     public function execute( event:Event ) : Void {
         // BusinessDelegate를 생성하고, login 메소드를 호출하는
         var delegate: CustomerDelegate = new CustomerDelegate( this );
         var loginVO : LoginVO = LoginVO( event.data );
         delegate.login( loginVO );
     }

     // 서버 측의 서비스 호출에 성공했을 경우의 핸들링
     public function onResult( event : Object ) : Void {
         ModelLocator.workflowState = ModelLocator.VIEWING_LOGGED
_IN_SCREEN;

         var loginDate : Date = Date( event.result );
         ModelLocator.loginDate = loginDate;
     }

     // 서버 측의 서비스 호출에 실패했을 경우의 핸들링
     public function onFault( event : Object ) : Void {
         ModelLocator.statusMessage = "Your username or password was wrong,
                                       please try again.";
     }
}



7. ModelLocator
2006/12/23  

ModelLocator

 ModelLocator는 Locator라는 이름이 붙어 있기 때문에 일견 J2EE 패턴의 하나일까하고 생각해 버립니다만, 이것은 Cairngorm 오리지날의 패턴입니다.역할로서는, 화면에 표시하는 모델을 보관 유지하는 것입니다.View(MXML)에서는, 이 ModelLocator를 참조해 화면의 표시를 실시합니다.

 아래의 리스트는, 로그인 샘플의 ModelLocator입니다.방금전의 LoginCommand 클래스에서 설정 한 속성을 가지고 있습니다.또, 화면 표시용의 데이터가 아닙니다만, workflowState라는 로그인이 끝난 상태인가 그렇지 않은가를 판단하는 속성을 가지고 있습니다.Index.mxml에서는, 이 workflowState가 ViewStack 컨테이너의 selectedChild 속성에 바인딩되어 있어서 이 값이 바뀜으로써 화면 천이를 하도록 되어 있습니다.

 ModelLocator는 Cairngorm Framework의 ModelLocator 인터페이스를 구현하여 작성합니다. 이것도 방금 전의 ValueObject와 같이 마커 인터페이스 때문에 어떤 메소드의 구현이 강제당하는 경우는 없습니다.

리스트 7 ModelLocator.as

class org.nevis.cairngorm.samples.login.model.ModelLocator
implements org.nevis.cairngorm.model.ModelLocator {
     // 로그인에 실패했을 때에 표시하는 에러 메세지
     public static var statusMessage : String;
     // 로그인에 성공했을 때에 표시하는 로그인 일자
     public static var loginDate : Date;

     // 로그인이 끝난 상태인가 그렇지 않은가를 판단하는 속성과 클래스 변수
     public static var workflowState : Number;
     public static var VIEWING_LOGIN_SCREEN : Number = 1;
     public static var VIEWING_LOGGED_IN_SCREEN : Number = 2;
}

AS2에 정수는 없는가?

 지금 보인 ModelLocator의 로그인이 끝난 상태인가 그렇지 않은가를 나타내는 1이나 2의 숫자나 Controller 클래스의 이벤트명은 클래스 변수가 아니라 정수인 편이 좋은 것이 아닌가 생각하는 분들이 있지 않습니까. 그렇습니다만 유감스럽게도 Action Script 2.0에서는 미리 정의된 정수(ENTER, SPACE 등)는 있지만 개발자가 프로그램으로 독자적으로 정수를 정의할 수는 없습니다. Action Script 3.0에서는 프로그램으로 정수를 정의하기 위한 “const” 키워드가 지원되어 정수를 정의할 수 있도록 되어 있습니다.




8. BusinessDelegate
2006/12/23  

BusinessDelegate

 BusinessDelegate는 J2EE 패턴 중 하나로 서비스의 구현이 무엇인지를 클라이언트에 대해서 은폐합니다. Flex 1.5에서는 서버 측에 액세스하는 방법이 3가지(RemoteObject, HTTPService, WebService)있는데, 서비스를 사용하는 측은 이들 서비스의 구현을 의식하지 않고 서비스에 액세스할 수 있습니다.

 아래의 리스트는 로그인 샘플의 BusinessDelegate인 CustomerDelegate입니다. constructor에서는 Cairngorm Framework의 ServiceLocator 클래스를 이용하여 “customerDelegate”라는 이름의 서비스를 룩업하였습니다.

 EJB의 홈 인터페이스나 데이터 소스 등이라면 JNDI에서 룩업하였는데 Cairngorm Framework는 브라우저의 Flash Player 상에서 동작하고 있기 때문에 이러한 J2EE의 구조는 이용할 수 없습니다. ServiceLocator는 이후에 설명할 Services라는 MXML 파일로부터 해당의 서비스를 찾기 시작합니다.

 login 메소드에서는 취득한 서비스의 login 메소드를 호출하여 서버 측의 서비스에 액세스합니다. 그 후에 Flex의 클래스 라이브러리인 Delegate 클래스를 사용하여 서비스 호출 성공 시와 실패 시의 핸들링을 Command 클래스에 위양(Delegate)합니다.

리스트 8 CustomerDelegate.as

class org.nevis.cairngorm.samples.login.business.CustomerDelegate {

     public function CustomerDelegate( responder : Responder ) {
         // ServiceLocator를 이용해 서비스를 룩업
         this.service = ServiceLocator.getInstance().getService( "customerDelegate" );
         this.responder = responder;
     }

     public function login( loginVO : LoginVO ): Void {
         // 서버 측의 서비스를 호출한다
         var call = service.login( loginVO );

         // 서비스 호출 성공 시와 실패 시의 핸들링을 Command에 위양
         call.resultHandler = Delegate.create( responder, responder.onResult );
         call.faultHandler = Delegate.create( responder, responder.onFault );
     }

     private var responder:Responder;
     private var service:Object;
}




9. Services
2006/12/23  

Services

 Services는 ServiceLocator에 의해서 룩업되는 서비스를 일원 관리해 두는 레지스트리와 같은 것입니다.클라이언트측으로부터 액세스하고 싶은 서버 측의 서비스는 모두 이 MXML에 정의합니다. 아래의 리스트는 로그인 샘플의 Services인 Services.mxml입니다.

 로그인 샘플에서는 서비스를 1개밖에 사용하지 않기 때문에 customerDelegate만이 정의되어 있습니다. <mx:RemoteObject> 태그를 사용하고 있기 때문에 서버 측의 서비스로서는 Remote Object를 사용한다는 것을 알 수 있지만 서비스의 구현 클래스까지는 알지못합니다. named 속성의“customerServiceImpl”는 구체적으로 어떤 클래스를 가리키는 것일까요.

리스트 9 Services.mxml

<cairngorm:ServiceLocator xmlns:mx="http://www.macromedia.com/2003/mxml"
                           xmlns:cairngorm="http://www.iterationtwo.com/cairngorm">

     <!-- 서버 측의 서비스를 정의 -->
     <mx:RemoteObject id="customerDelegate" named="customerServiceImpl"
                      protocol="http"
                      showBusyCursor="true"
                      result="event.call.resultHandler( event )"
                      fault="event.call.faultHandler( event )">
     </mx:RemoteObject>

</cairngorm:ServiceLocator>

 Remote Object를 사용한 적이 있는 독자라면 알 것으로 생각합니다만 Remote Object를 사용하려면 Flex의 설정 파일인 WEB-INF/flex/flex-config.xml에 정의를 해두어야 합니다.

 아래의 리스트는 로그인 샘플의 flex-config.xml입니다. <remote-objects> 태그 내에 “customerServiceImpl”라는 이름으로 Remote Object가 1개 정의되어 있음을 알 수 있습니다. <source>태그에 정의되어 있는 Java의 클래스가 서비스(Remote Object)의 구현이 됩니다. 이 Java 클래스에서 로그인의 처리를 실시하고 성공했을 경우에는 로그인의 일자를 설정하도록 되어 있어서 실패했을 경우에는 예외를 슬로우하도록 되어 있습니다.

리스트 10 flex-config..xml(발췌)

<?xml version="1.0" encoding="EUC-KR"?>
<flex-config xmlns="http://www.macromedia.com/2003/flex-config">

   <remote-objects>

     <whitelist>
       <!-- whitelist config for named objects -->
       <named>
         <!-- CAIRNGORM LOGIN SAMPLE -->
         <!-- 서비스에 붙이는 이름 -->
         <object name="customerServiceImpl">
           <!-- 서비스의 구현 클래스 -->
           <source>
             org.nevis.cairngorm.samples.login.business.CustomerDelegate
           </source>
           <type>stateless-class</type>
         </object>
       </named>
     </whitelist>
       
   </remote-objects>
</flex-config>

  이상으로 이번 회에는 로그인 샘플의 원시 코드를 보면서 Cairngorm Framework의 아키텍쳐에 대해 해설했습니다. 제1회 「개발 품질을 균일화시키는 Cairngorm Framework」에서 Cairngorm Framework의 특징으로 든 객체 지향, 디자인 패턴의 콜라보레이션(마이크로 아키텍쳐), 이벤트 리스너 모델이 실천되고 있음을 알 수 있었다고 생각합니다.

 다음 회에는 실제로 샘플 애플리케이션을 작성할 예정입니다.

Cairngorm Store

 Cairngorm Framework에는 본 연재에서 소개한 로그인 샘플 외에 Flex Store(Flex에 부속되어 있는 쇼핑 사이트 샘플)를 Cairngorm Framework를 사용해 다시 만든 Cairngorm Store라는 샘플도 부속되어 있습니다. 이 쪽은 보다 실천적인 샘플이 되므로 흥미가 있는 분은 꼭 봐 주시기 바랍니다.