Cairngorm Framework
1. Cairngorm Framework 정의
cairngorm은 사전적인 의미로는 연수정이란 뜻입니다.
발음을 하면 컨검? 주위에서는 그냥 캔곰이라고 부르더군요. 이하 강좌는 캔곰이라는 용어를 사용하여 진행하도록 하겠습니다. 알아서 이해해 주시면 감사…^^
캔곰 프레임워크는 Flex를 위한 작은 규모의 프레임워크입니다. 기존에 사용하던 프레임워크와는 차이가 많이 나죠. 저도 처음엔 뭐 이런게 프레임워크인가 생각했던 적이 있습니다. 하지만 그래도 몇가지 사항에서 중요합니다.
캔곰은 Flex Application을 사용하여 Enterprise Software를 개발하기 위한 디자인패턴들로 구현되어 있습니다. 또한 캔곰 사용의 장점은 동일한 패턴으로 서비스를 정의하고 관리함으로서 간결한 코드를 작성할 수 있습니다. 단점은 파일 개수가 많아 진다는 것이 아닐까 싶네요.
2. 캔곰 프레임워크 설치하기
캔곰 프레임워크는 Flex에서 사용하는 라이브러리 포맷인 swc 형태로 배포됩니다. 또한 소스코드까지 포함되어 있으므로 좀 더 구체적인 내용을 알고 싶은 분들은 소스코드를 분석하셔도 됩니다.
2.1 캔곰 프레임웍2.1을 다운로드 합니다.
URL : http://labs.adobe.com/wiki/index.php/Cairngorm
<그림 1>
2.2 다운로드 받은 파일의 압축을 풉니다.
압축을 풀면 bin 폴더에서 Cairngorm.swc 파일을 확인할 수 있습니다.
<그림 2>
2.3 프로젝트의 library path로 이동한 다음 ‘Add SWC’버튼을 클릭 한 후 bin폴더에 있는 Cairngorm.swc파일을 추가합니다.
<그림 3>
3. Cairngorm Framework 구조
3.1 캔곰은 MVC구조 형태로 패턴화 되어 있습니다. 프리젠테이션과 비즈니스 로직을 분리 할 수 있는 형태의 템플릿을 제공합니다.
3.2 캔곰 architecture
<그림 4>
- View : End User의 View화면을 지칭합니다. View는 사용자의 이벤트를 받아 CairngormEventDispatcher를 사용하여 Controller에 등록되어 있는 커맨드를 호출하는 역할을 담당합니다.
- Model : Controller와 View를 중계하는 역할을 담당합니다. 최종적으로 처리된 결과를 ModelLocator를 통해 View에 전달됩니다.
- Controller : Command를 실행하여 서비스를 요청하는 역할을 담당합니다. 처리된 결과는 ModelLocator를 통해 View에 전달됩니다.
3.3 캔곰 패키지 구조
각각의 기능 그룹별로 패키지 폴더를 구성합니다. 뭐 반드시 지켜야 하는 구조는 아니지만 되도록이면 동일한 형태의 Naming Rule을 사용하기를 권장합니다.
- Business : Delegate 클래스를 모아 놓은 폴더입니다. 그리고 데이터 서비스를 정의하는 Services.mxml도 이곳이 포함됩니다.
- Commands : Delegate를 호출하고 리턴된 결과 값을 View에 전달하는 역할을 담당하는 command 클래스를 모아 놓은 폴더입니다. Command 클래스는 캔곰에서 제공하는 Command,Responder 인터페이스를 상속받아 구현합니다.
- Control : command를 관리하는 controller 클래스를 모아 놓은 폴더입니다. CairngormEventDispatcher를 통해 Control에 등록된 Command를 실행합니다. Controller 클래스는 캔곰에서 제공하는 FrontController를 상속받아 구현합니다.
- Model : View들을 관리하는 역할을 담당하는 ModelLocator를 모아 놓은 폴더입니다. ModelLocator 클래스는 캔곰에서 제공하는 ModelLocator클래스를 상속받아 구현합니다(개인적으로는 사용 안 함).
- Vo : RemoteObject서비스를 사용할때만 해당되는 클래스일 듯 합니다. Value Object의 약어로서 View에서 표시될 속성들을 모아놓은 클래스입니다. Vo는 ValueObject를 상속받아 구현합니다. Vo사용의 장점은 타입 체크를 통해 좀 더 명확하게 무슨 정보 인지를 판단 할 수 있습니다.
4. 캔곰 사용하기
예제로 게시판 리스트와 게시글 읽기 기능 두 가지를 가지고 캔곰을 적용해 서비스 데이터를 연동해 보도록 하겠습니다. 단 RemoteObject를 정의하여 자바 클래스를 호출하는 부분은 “RemoteObject 사용하기” 강좌에서 계속 진행 할 예정입니다.
4.1 프로젝트의 패키지를 아래와 같이 business,command,control,event,model,view.vo를 정의합니다.
<그림 5>
4.2 이벤트 정의
- ViewEvent.as : CairngormEvent를 상속받은 클래스로서 리턴 페이지 객체를 저장하기 위한 view 속성을 포함하고 있습니다. 추후 커맨드를 호출하기 위해서는 반드시 ViewEvent를 생성하여 사용해야 합니다
package sample.event { import com.adobe.cairngorm.control.CairngormEvent; import mx.core.UIComponent; public class ViewEvent extends CairngormEvent { //view객체를 저장하기 위한 속성 public var view:UIComponent; public function ViewEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false) { super(type, bubbles, cancelable); } } } |
- ServiceResultEvent.as : 서비스 결과를 전달하기 위한 이벤트 입니다. 결과 값을 저장하기 위한 result속성을 포함하고 있습니다.
package sample.event { import flash.events.Event; public class ServiceResultEvent extends Event { public var result:*; //이벤트 이름 public static const EVENT_SERVICE_RESULT:String = "serviceResult"; public function ServiceResultEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false) { super(type, bubbles, cancelable); } } } |
4.3 Delegate 정의
- BBSServiceDelegate.as : ServiceLocator를 사용하여 RemoteObject 서비스를 호출하고 리턴된 결과값을 command에 전달합니다. 서비스 호출은 AsyncToken을 사용하여 비동기 형태로 호출됩니다. RemoteObject를 이용한 코드는 다음 강좌에 진행하기 때문에 임시로 주석처리 하였습니다.
package sample.business { import sample.event.ViewEvent; import com.adobe.cairngorm.business.Responder; import com.adobe.cairngorm.business.ServiceLocator; import mx.rpc.AsyncToken; import mx.collections.ArrayCollection; import flash.utils.setTimeout; import sample.vo.BBSData; public class BBSServiceDelegate { private var responder:Responder; private var serivce:Object; public function BBSServiceDelegate(responder:Responder) { //정의된 RemoteObject의 id값으로 서비스 객체를 얻어 옵니다. //this.serivce = ServiceLocator.getInstance().getService("BBSService"); this.responder = responder; } public function getBBSList(event:ViewEvent):void { var dataArr:ArrayCollection = new ArrayCollection(); var obj:BBSData = new BBSData(); obj.num = 1; obj.subject = "aaaa"; obj.writer = "lee"; dataArr.addItem(obj); var resultObj:Object = new Object(); resultObj.result = dataArr; setTimeout( responder.onResult, 100, resultObj ); //var token:AsyncToken = service.getBBSList(); //token.resultHandler = responder.onResult; //token.faultHandler = responder.onFault; } public function getBBSRead(event:ViewEvent):void { var obj:BBSData = new BBSData(); obj.num = 1; obj.subject = "aaaa"; obj.writer = "lee"; var resultObj:Object = new Object(); resultObj.result = obj; setTimeout( responder.onResult, 100, resultObj ); //var token:AsyncToken = service.getBBSRead(event.data.rowNum); //token.resultHandler = responder.onResult; //token.faultHandler = responder.onFault; } } }
|
4.4 Command 정의
- BBSListCommand.as : 게시판 리스트 command입니다. BBSServiceDelegate function을 호출한후 결과 값을 view 속성을 사용하여 ServiceResultEvent 이벤트를 발생시킵니다.
package sample.command { import com.adobe.cairngorm.control.CairngormEvent; import com.adobe.cairngorm.commands.Command; import com.adobe.cairngorm.business.Responder; import sample.event.ViewEvent; import sample.event.ServiceResultEvent; import mx.core.UIComponent; import sample.business.BBSServiceDelegate; import mx.collections.ArrayCollection; import sample.vo.BBSData; public class BBSListCommand implements Command, Responder { private var view:UIComponent; public function execute(event:CairngormEvent):void { var viewEvt:ViewEvent = ViewEvent(event); //호출한 View. 결과를 리턴할때 사용함. view = viewEvt.view; //Delegate 클래스 호출 var delegate : BBSServiceDelegate = new BBSServiceDelegate( this ); delegate.getBBSList(viewEvt); } public function onResult(event:*=null):void { var res:ServiceResultEvent = new ServiceResultEvent(ServiceResultEvent.EVENT_SERVICE_RESULT); res.result = event.result; //호출한 view의 "serviceResult" 이벤트를 발생시킴 view.dispatchEvent(res); } public function onFault(event:*=null):void { } } } |
4.5 Controller 정의
- BBSController.as : 게시판 관련 이벤트를 관리하는 역할을 담당합니다. 등록된 이벤트 들은 CairngormEventDispatcher를 사용하여 실행됩니다.
package sample.control { import com.adobe.cairngorm.control.FrontController; import sample.command.BBSListCommand; import sample.command.BBSReadCommand;
public class BBSController extends FrontController { public static const EVENT_BBS_LIST : String = "bbs_list"; public static const EVENT_BBS_READ : String = "bbs_read"; public function BBSController() { addCommand( BBSController.EVENT_BBS_LIST, BBSListCommand ); addCommand( BBSController.EVENT_BBS_READ, BBSReadCommand); } } } |
4.6 Vo 정의
- BBSData.as : 게시판에서 사용되는 데이터 속성 값을 정의 한 클래스입니다.
package sample.vo { import com.adobe.cairngorm.vo.ValueObject; [Bindable] public class BBSData implements ValueObject { public var num:int; //번호 public var subject:String; //제목 public var content:String; //내용 public var writer:String; //작성자 } } |
4.7 View 정의
- 이제부터 모든 사용자 View들에 대한 컴포넌트들은 view 패키지 아래에서 정의한 다음 네임스페이스 정의를 통해 접근하는 형태로 사용합니다. 그리고 서비스를 호출하는 페이지들은 아래와 같이 이벤트를 정의하고 initialize 시점에 이벤트를 등록하여 처리하는 형태로 작성됩니다.
*사용자 이벤트 정의
<그림 6>
*initialize 이벤트
<그림 7>
* serviceResult” 이벤트 처리
<그림 8>
- BBSListView.mxml : 게시판 리스트를 구현한 MXML 컴포넌트 입니다. CairngormEventDispatcher를 사용하여 command를 호출하고 “serviceResult”를 등록하여 결과 리턴 이벤트를 전달받아 DataGrid에 Binding을 합니다.
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%" initialize="initView()"> <mx:Metadata> [event(type="serviceResult","sample.event.ServiceResultEvent")] </mx:Metadata> <mx:Script> <![CDATA[ import mx.managers.PopUpManager; import mx.collections.ArrayCollection; import sample.event.ServiceResultEvent; import sample.event.ViewEvent; import com.adobe.cairngorm.control.CairngormEventDispatcher; import sample.control.BBSController; import com.adobe.cairngorm.control.CairngormEvent; [Bindable] private var listdata:ArrayCollection; private function initView():void { this.addEventListener("serviceResult",resultEvt); //BBS 리스트를 요청하는 이벤트를 생성합니다. var event:ViewEvent = new ViewEvent(BBSController.EVENT_BBS_LIST); //결과값을 받기위해 현재 페이지 객체를 파라미터로 전달 합니다. event.view = this; //Controller에 등록된 Command를 실행 합니다. CairngormEventDispatcher.getInstance().dispatchEvent( event ); } private function resultEvt(event:ServiceResultEvent):void { //리턴받은 결과값을 데이터 그리드에 Binding 합니다. this.listdata = event.result; } private function changeEvt():void { //상세보기 화면을 띄어줍니다. var readView:BBSReadView = PopUpManager.createPopUp(this,BBSReadView,true) as BBSReadView; readView.rowNum = 1; PopUpManager.centerPopUp(readView); } ]]> </mx:Script> <mx:DataGrid width="100%" height="100%" dataProvider="{listdata}" change="changeEvt()"> <mx:columns> <mx:DataGridColumn headerText="번호" dataField="num"> </mx:DataGridColumn> <mx:DataGridColumn headerText="제목" dataField="subject"> </mx:DataGridColumn> <mx:DataGridColumn headerText="작성자" dataField="writer"> </mx:DataGridColumn> </mx:columns> </mx:DataGrid> </mx:HBox>
|
4.8 완성된 전체 게시판 구조는 아래 그림 형태로 실행됩니다
<그림 9>
처음 시작하시는 분들은 여러 개의 파일을 생성하여 서비스를 구현하는 형태가 번거롭다고 생각할지도 모르나 추후 프로젝트를 진행하면서 새로운 기능들이 추가되고 이전 기능들이 수정될 경우 동일한 패턴을 사용하므로 서비스 변경이 용이합니다. 그리고 캔곰에 대해 어느정도 익숙해지면 나름대로 프로젝트 성격에 맞는 형태로 수정하여 재사용할 수도 있습니다. 나름대로 고민해 보길 바랍니다.
다음은 RemoteObject에 대해
지금까지 각각의 캔곰 클래스들이 담당하는 역할과 이를 활용하여 게시판 리스트를 구현하는 방법에 대해 알아 보았습니다. 다음 시간에는 RemoteObject에 대해 알아보도록 합니다.