scaleform.minarto.com

Binding reboot - 0 본문

Communication

Binding reboot - 0

미나토 2013. 6. 11. 17:00


예전에 애드온 UI 편을 빌어서 Binding 에 대해서 다뤘던 적이 있습니다



누누히 말하지만 포스팅으로 올리는 코드는 포스팅 자체를 위해서 만든 코드인지라 막 만듭니다.

(테스트도 안합니다 ㅡㅡ)



제 스스로 말하기는 뭐하지만 Binding 클래스는 참... 그리고 엄청 좋은 녀석입니다.


하나의 클래스 자체로 인해 UI프레임웍을 바꿀 수도 있고, 개발 프로세스가 바뀌는 녀석이죠...

(소망이 있다면 CLIK 배포시에 이녀석도 같이 배포되었으면 할 정도로 제가 자신하며 좋아하는 클래스입니다)



얼마 전에 스터디를 갔다가 A 회사의 H 군께서 실제 제 코드를 적용해보고 사용하고 있다는 얘기를 들어서... 제대로 포스팅을 다시 해볼까 합니다.

(실제는 저도 안씁니다. 나빠서 안쓰는게 아니고 이미 잘 돌아가고 있는데 새로운 방식으로 바꿀 이유가 없어서요...)


이번엔 그 녀석을 좀 개선해봤습니다.



그럼 그 녀석에 대해서 한번 시작해보죠


as2 용 링크, as3 용 링크


/**
 * 
 */
package com.minarto.data {
	import flash.events.TimerEvent;
	import flash.external.ExternalInterface;
	import flash.utils.Timer;
	
	
	public class Binding {
		private static var valueDic:* = {}, bindingDic:* = {};
		
		
		/**
		 * 초기화 및 위임
		 *  
		 * @param $delegateObj	위임 객체
		 *  
		 */		
		public static function init($delegateObj:*):void{
			if ($delegateObj)	$delegateObj.setValue = set;
			else ExternalInterface.call("Binding", Binding);
		}
		
		
		/**
		 * 값 설정 
		 * @param $key	바인딩 키
		 * @param $value	바인딩 값
		 */
		public static function set($key:String, $value:*):void {
			var a:Array, i:Number, l:Number, item:*, arg:Array;
			
			if($value == valueDic[$key])	return;
			
			valueDic[$key] = $value;
			
			a = bindingDic[$key];
			for (i = 0, l = a ? a.length : 0; i < l; ++ i) {
				item = a[i];
				arg = item.arg;
				arg[0] = $value;
				item.handler.apply(null, arg);
			}
		}
		
		
		/**
		 * 바인딩 여부
		 */				
		public static function has($key:String, $handler:Function):Boolean {
			var a:Array = bindingDic[$key];
			
			for ($key in a) if (a[$key].handler == $handler) return	true;
			return	false;
		}
		
		
		/**
		 * 바인딩 
		 * @param $key		바인딩 키
		 * @param $handler	바인딩 핸들러
		 * @param $args		바인딩 추가 인자
		 */				
		public static function add($key:String, $handler:Function, ...$args):void {
			var a:Array = bindingDic[$key], i:*, item:*;
			
			$args.unshift(get($key));
			
			if(a){
				for (i in a){
					item = a[i];
					if (item.handler == $handler){
						item.arg = $args;
						return;
					}
				}
				item = {handler:$handler, arg:$args};
				a.push(item);
			}
			else{
				item = {handler:$handler, arg:$args};
				bindingDic[$key] = a = [item];
			}
		}
		
		
		/**
		 * 바인딩 해제
		 * @param $key	바인딩 키
		 * @param $handler	바인딩 핸들러
		 * 
		 */			
		public static function del($key:String, $handler:Function):void {
			var a:Array, i:*;
			
			if($key){
				a = bindingDic[$key];
				for (i in a) {
					if (a[i].handler == $handler){
						a.splice(i, 1);
						if(!a.length)	delete	bindingDic[$key];
						return;
					}
				}
			}
			else	bindingDic = {};
		}
		
		
		/**
		 * 특정 바인딩 값을 가져온다 
		 * @param $key	바인딩키
		 * @return 바인딩 값
		 * 
		 */		
		public static function get($key:String):* {
			return	valueDic[$key];
		}
	}
}




as3 용 코드로 설명해드리겠습니다


(as2 용 코드는 최적화를 위해서 클로저와 메소드 오버로드를 마구 사용해서 구현했기에, 클로저와 메소드 오버로드를 모르시는 분들에게 설명하기가 난감해서리...)




1. public static function init($delegateObj):Void



가장 처음에 있는 init 함수를 보죠.


초기화 함수입니다. 클라이언트에게 Binding 객체를 넘겨서 통신을 가능하게 하거나 위임 객체를 인자로 받아서 Binding 객체와의 통신이 필요하지 않게 만들 수 있습니다.



이게 무슨 말이고 하니...



예를 들어서 main(즉 root) 클래스에다가 setValue 이라는 메소드를 만들어놓습니다. 그러고선 Binding.init(main) 이라고 main 클래스에서 정의해서 실행하는 순간 main.setValue 함수는 Binding.set 메소드를 위임하게 됩니다.


그러면 클라이언트는 Binding 객체를 관리할 필요가 없어집니다. 


UI 통신을 위해서 클라이언트는 root 는 이미 관리하고 있을 것이고 클라이언트는 인보크 함수 실행하듯이 그냥 root.setValue 를 사용하면 됩니다.

클라의 일손을 줄여주는 거죠.


물론 인자를 안주면 기존처럼 그냥 Binding 객체를 사용할 수 있습니다.



참고로 몇몇분들께서 착각하고 계신 것들이 있는데...



new Binding 이라고 객체를 만들거나 싱글턴을 만들어야만 사용할 수 있다고 생각하시는 분들이 있습니다.


하지만 저는 바로 


ExternalInterface.call("Binding", Binding);


이런 식으로 클래스 자체를 넘겨버렸습니다. 싱글턴을 구현하기 위해서 꼭 인스턴스를 생성할 필요는 없는 겁니다.


그냥 static 메소드로 활용해버리면 되니까요...



게다가 root 에서 init 을 하다보면 또 다른 장점이 있습니다.



혹시라도 Binding 코드가 수정되었다고 한들, 먼저 root 에서 실행되었기에 root 의 클래스가 일괄 적용되죠... 따로 오버로드를 하지 않는 한 말입니다.



다음은 예제 코드입니다.



import com.minarto.data.Binding;
var setValue:Function;

Binding.init(this);

function f($v):void{
	trace($v)
}
Binding.add("kkk", f);


Binding.set("kkk", 1111);
setValue("kkk", 2222);



///////////

1111

2222

////////////////


이런 결과가 나올겁니다



이런 식으로 Binding 클래스의 Binding.set 메소드를 그대로 사용할 수도 있지만 그냥 root 의 setValue 를 사용해서 쓸 수도 있는 겁니다.


클라이언트는 Binding 클래스는 전혀 몰라도 되는 것이죠



링크된 실제 소스 코드에는 dateInit 이란 메소드가 있지만 그건 시간을 관리하기 위한 별도의 api에 가까우니 생략을 하도록 하고 다음 포스팅에서는 set 함수를 살펴보도록 하죠