=================================
=================================
=================================
[출처]: http://cafe.naver.com/flexcomponent/10241
( 출처 : AS3 language 101 for C/C++ coders 옮김 : 췌영(rick@atoonz.com))
웹서핑을 하다가 괜찮은 글이 있어서 옮겨봅니다. 제 경우에는 도움이 많이 됐습니다만 다른분은 다들 알고 계실지도 모르겠네요.. ^^; 글은 2개로 나뉘어져 있구요, 2번째 글도 우리말로 모두 옮기고 나서 올리도록 하겠습니다.
AS3 language 101 for C/C++ coders - 1
이 아티클은 C++프로그래머들이 Flex나 Flash에서 ActionScript3 개발을 하는 것에 도움을 주기 위한 관점으로 작성되었다. 나는 C/C++ 을 나의 커리어를 쌓는데 이용해왔다. 나는 또한 자바스크립트와 펄에 관해서도 상당한 경험을 가지고 있는데, ActionScript 3 은 이런 모든 언어들의 흥미로운 점을 모두 보여준다. 액션스크립트는 ECMA4스팩을 따르고 있다. 그래서 이것은 '표준 언어' 이다. AS3은 표준 언어 체계에 플래시/플랙스를 위한 커스텀 클래스 프레임워크를 포함한다. 아래있는 내가 개인적으로 AS3에서 찾은 흥미로운 부분들 이다.
타입정의
C/C++과 비교해보아, 가장 먼저 느끼는 다른점은 AS3이 변수명을 선언하는 방법이다. 모든 타입 선언은 post-fix(뒤에 붙여..) 로 한다. 예를 들어 C언어에서는 다음과 같이 할 것이다.
int myFunction(char *str);
하지만 AS3에서는 함수 선언을 다음과 같이 한다.
function myFunction(str:String) : int
타입캐스팅
AS3에서 타입캐스팅은 타입의 생성자를 호출하는 것이라 생각할 수 있다. 아래 코드는 우리가 하고싶은 것(타입캐스팅)에 대해서 보여준다. C 에서 타입캐스팅은 아래와 같이 한다
int i = (int)somefloat;
하지만 AS3에서 타입캐스팅에서는
var i:int = int(somefloat);
위와 같이 한다. 마치 생성자를 호출하는 것 처럼 보이지만 new연산자를 사용하지 않는 이상 생성자가 호출되지는 않는다. 단지 타입캐스팅이 될 뿐이다. 예를 들어보면
var foo:SomeClass = SomeClass(someObject);
var bar:SomeClass = new SomeClass(someObject);
첫번째 줄은 "someObject" 을 SomeClass로 타입캐스팅 하는 것이다. 두번째 줄은 새로운 SomeClass 를 "someObject"를 생성자의 인자로 넘기며 인스턴스화 하는 것 이다. 이 미묘한 차이지만 큰 차이를 유발한다. 생성자가 파라미터를 가지는 경우에는 위의 코드가 컴파일에러나 컴파일경고가 발생하지 않기 때문에 주의하여 사용하여야 한다. 타입캐스트와 객체인스턴스와 다른점은 오직 'new'키워드 뿐이다.
변수 범위
변수들은 함수에 의해서 범위가 제한된다. 액션스크립트는 "variable hoisting"이라 불리는 시스템을 사용한다. 이것은 함수 내의 모든 변수가 컴파일 타임에 함수의 첫 부분에 모두 정의 되는 시스템을 이야기 한다. (함수 안에 블럭이 있건 없건 중요치 않다) 예를 들어보자.
public function doSomething() : void
{
var foo:int = 4;
if (foo)
{
var bar:int = 2;
}
}
"viable hoisting"에 의해, 함수안에 선언된 모든 변수들은 컴파일 타임에 함수의 맨 처음으로 옮겨진다. 위의 예제 소스는 컴파일 타임에 아래와 같은 형태로 변경될 것 이다.
public function doSomething() : void
{
var foo:int;
var bar:int;
foo = 4;
if (foo)
{
bar = 2;
}
}
"bar" 변수가 함수 전역에 걸친 범위를 가지게 된 것을 확인하자. AS3의 이런 미묘한 변수 (위치)조정은 의도하지 않은 상황을 유발하기도 한다. 그렇기 때문에 "bar"변수를 "if(foo)"앞에 사용하는 어떤 행위도 유효하다. 소스코드에서는 bar를 if 블록 안에서 선언했더라도 말이다. 하나의 함수에 같은 이름의 변수를 여러개 만들면 AS3은 컴파일시 불평을 늘어놓겠지만, 선언하기 전에 사용하는 것에 대해서는 불평하지 않을 것이다.
와일드카드 자료형
AS3에서는 다른 형태로 바꾸기 쉬운 와일드카드타입 ( C에서는 void* )를 사용할 수 있다. 예를 들자면, 여러가지 오브젝트를 리턴할 수 있는 펙토리객체가 있다고 해보자, 이것은 다음과 같이 사용할 수 있을 것 이다.
public function wildcard() : void
{
var anything:* = ObjectFactory.getData();
}
런타임 자료형 검사
와일드카드 자료형이 있으니, 런타임에 와일드카드를 원래 자료형을 확인하는 방법 또한 필요하다. 이것을 하기위해 "is" 연산자를 사용할 수 있다.
public function doSomething() : void
{
var something:* = getData();
if (something is String)
{
// handle string logic
}
else
{
// do something else
}
}
이것은 런타임에 자료형을 검사할 수 있게 해주기 때문에, 오브젝트가 무엇이냐에 따라서 다른 로직을 수행할 수 있도록 만들어준다.
함수 오버로딩 없음
AS3에는 함수 오버로딩이 없다. 하지만 함수 오버로딩을 흉내내는 시스템을 구현할 수는 있다. 그 C++ 에선 오버라이딩을 사용하기 위해 다음과 같은 코드를 사용할 것이다.
int doSomething(int i);
int doSomething(char *str);
AS3에서는 오버로딩을 할 수 없다. 하지만 와일드카드인 "*" 와 "is" 런타임 자료형체크를 이용하여 함수오버로딩을 흉내낼 수 있게 해준다. 예를 들면 다음과 같다.
function doSomething(obj:*) : int
{
if (obj is int)
// do int stuff
else if (obj is String)
// do string stuff
else
// what type did you give me?
}
연산자 오버라이딩 없음
AS3에서는 "+"나 "=" 따위의 연산자를 오버라이딩 할 수 있는 방법이 없다. 가장 유사한 기능은 get/set 맴버 접근자로 클래스 맴버변수에 대해 값(혹은 참조)을 얻거나 대입 할 수 있게 해주는 것이 있다.
모든 것은 오브젝트 이다.
AS3에서 사용되는 모든 타입의 클래스들은 "Object"라는 클래스에서 파생된 클래스이다. 심지어는 아무 클래스도 상속받지 않더라도 "Object"를 기본적으로 상속받는다. 이것은 함수인자로 무엇이든 전달할 수 있다는 것을 의미하기도 한다. 어떤 경우인지 상관 없이 데이터의 레퍼런스를 인자로 넘길 수 있다. 불려진 함수가 인자로 넘어온 객체를 수정하면 인자로 넘기기 전에 가지고 있던 버젼도 수정된다 (역:C++의 레퍼런스와 같은 기능.) int, Number, String등의 "기본 자료형"들에 대해서는 약간의 예외상황이 있는데, 이것들도 Object를 상속받은 자료형이긴 하지만, 이것들의 레퍼런스 카운팅기능 덕분에 스택오브젝트 처럼 동작한다. 이런 기본자료형은 함수인자로 넘어갈 때 새롭게 인스턴스화 되어 복사본이 전달되어 진다. 그렇기 때문에 함수 내부에서 수정하여도 원본이 바꾸지 않는다.
하나의 파일에 하나의 패키지, 클래스만
AS3 에서 클래스들을 만들 때, 하나의 AS파일에는 하나의 패키지와 그 안에 하나의 클래스만을 정의할 수 있다.
//파일명 MyClass.as
package my.class.package
{
public class MyClass
{
public function MyClass()
{
...
}
}
}
그림. 1
//파일명 MyClass.as
package my.class.package
{
public class MyClass
{
public function MyClass()
{
...
}
}
}
class MyPrivateClass
{
public function MyPrivateClass()
{
...
}
}
그림. 2
//파일명 MyClass.as
package my.class.package
{
public class MyClass
{
public function MyClass()
{
...
}
}
public class AnotherClass
{
public function AnotherClass
{
...
}
}
}
그림. 3
그림1과 그림2는 유효한 AS3 파일이다. 그림3은 유효하지 않다. AS3 은 파일당 하나의 패키지이상 정의하는 것이나, 그 패키지 안에 여러개의 클래스를 정의하는 것을 허용하지 않는다. 흥미로운 점은 그림2에 보여지는 "PrivateClass"인데 이 클래스는 파일 내부에서만 접근이 가능하다. 파일 외부에서 "PrivateClass"는 알려지지 않은 자료형이 된다. 구현중에 사용된 일부 클래스를 숨기려면 그림2와 같이 코드를 작성하면 된다. 공개된 클래스가 하나여야만 한다는 제한이 큰 말썽을 유발하진 않는다. 하지만 여러개의 클래스를 정의하고 싶을 경우 불편하게 여겨질 수도 있다. 적절히 파일 구조를 계획하도록 하자.
가상함수
C++과 AS3의 두드러진 차이점은 "override" 키워드를 이용하지 않는 이상 부모클래스의 함수를 오버라이딩 하지 않는 다는 것 이다. 이 키워드를 사용하지 않으면 모든 경우 부모클래스의 함수가 호출된다. C++의 "virtual" 키워드와 반대되는 것이라 생각할 수 있다. C++에서는 함수가 한번 "virtual"로 정의되면, 이 클래스에서 파생된 모든 클래스에서 이 함수를 "virtual"로 취급한다. AS3에서는 파생된 클래스(자식클래스)에서 어떤 함수가 "virtual"함수인지 조절한다.
다이나믹캐스트 (dynamic_cast)
AS3에서는 인터페이스를 사용하게 된다. 이것은 C++의 추상클래스와 비슷한 컨셉의 것이다. 인터페이스를 구현한 객체는 해당 인터페이스의 인스턴스로 전달되어질 수 있다. (역:C++에서의 추상클래스는 인스턴스화가 되지 않지만 AS3에서는 포인터라는 것이 없기 때문에 인스턴스화가 됩니다. 단, new를 이용하지 않을 뿐이죠.) 전달 받은 인터페이스의 인스턴스가 실제로 어떤 클래스(인터페이스를 구현한)인지 확인하기 위한 방법은 무엇이 있을까? "as"키워드를 사용하면 된다. 예를들어
var someInterface:ISomeInterface = factory.getSomeInterface();
var someClass:SomeClass = (someInterface as SomeClass);
"someInterface"가 실제로는 "SomeClass"의 인스턴스이거나 "SomeClass"의 파생된 클래스라면, "someClass" 변수는 "SomeClass"형의 (C++에서 이야기하는)레퍼런스가 될 것이다. 그렇지 않고 상관이 없는 다른 클래스의 파생 클래스라면 "someClass"는 null이 된다.
저수준 문자, 문자열
AS3은 "String"이고 불리는 원시적인 문자열 자료형을 가지고 있다. 각각 문자들을 접근할 수 있고 문자들을 이용해서 어떤 일들을 할 수 있다. 저수준 ASCII나 UTF8 값에 직접 접근하려면 어떻게 해야하는가? 이것에 가장 쉬운 방법은 ByteArray 클래스를 이용하는 것이다. 문자열을 ByteArray에 써 넣어 저수준 데이터로 사용할 수 있다. (역: writeMultiBytes 를 이용해서 ASCII 코드 문자열을 얻을 수 writeUTFBytes를 이용해서 UTF8 로 인코딩된 문자열을 얻을 수 있습니다.)
AS3 language 101 for C/C++ coders - 2
메시지루프를 제어할 수 없다.
전통적인 C/C++ 프로그램에서는 메모리에 프로그램이 계속 상주하여 작동하기 위해서 무한루프 (windows 에서는 메시지루프)를 이용한다. 이때 프로그래머는 이 루프의 흐름을 완전히 제어할 수 있지만 플래시에서는 가능하지 않다. 액션 스크립트에서 이 메인 메시지 루프는 플래시 플레이어에 의해서 제어되기 때문이다. 그것은 브라우져를 통해서, 혹은 플래시 플레이어 단독으로, 아니면 다른 응용 프로그램이 될 수도 있다. 플래시는 순수한 이벤트에 의해서 작동한다. 우리의 플래시 프로그램은 사용자이벤트와, 응용프로그램의 명령, 네트워크 응답 등을 포함한 모든 종류의 메시지 통지를 받는다. 이것은 어떤 이유에서도 액션스크립트가 Blocking 될 수 없음을 의미한다. 만약 우리의 플래시 프로그램이 루프에 의해서 Blocking 되었다면(혹은 부하가 많은 연산에 의해서 딜레이 되고 있다면 플래시 플레이어 자체가 완전히 멈춘것이라 볼 수 있다. 플래시는 모든것이 비동기 Callback 방식을 이용해 컨트롤 되어야 한다.
C/C++로 작성된 전형적인 응용프로그램에서는 Modal Dialog (대화상자, 혹은 메시지박스등)가 메시지루프를 관리한다. 이것은 이 Modal Dialog가 사용자의 입력에 의해서 끝날 때 까지 모든 프로그램이 중지해 있도록 구현하는 것을 가능하게 한다. 하지만 이것은 액션스크립트에서는 해당되지 않는다. 액션스크립트에서 Modal Dialog를 구현하려면 일단 화면에 창을 띄우고 해당 함수 (DoModal 같은..)가 리턴되고, 사용자의 입력 Click이벤트등의 callback 을 기다려야 한다. 이것은 또한 Alert(또는 MessageBox) 기능을 이용해서 디버깅하는 것이 Alert에 의해서 프로그램이 중지하지 않기 때문에 별로 유용하지 못함을 의미하기도 한다.
플랙스빌더 팀에 있는 Sho Kuwamoto는 "비동기 이벤트 다루기"와 관련된 아티클들을 작성하고 있다. 지금까지 1편 2편 3편 이 나와있다. 나는 이 아티클들을 아주 강력 추천한다. 이것들은 AS3의 비동기 환경에 관한 양질의 정보들을 제공할 것이다.
싱글쓰레드
플랙스 혹은 플래시에서는 우리의 프로그램은 싱글쓰레드로 실행된다. 만일 다중 쓰레드들을 사용해 왔다면 이런 상황이 답답하게 느껴질 것이다. 하지만 완전히 모든 AS3.0프로그램이 비동기, 이벤트주도 방식으로 돌아가기 때문에 AS3.0은 비동기 콜백 방식을 사용해서 프로그래밍 할 수 있는 나이스한 언어이기도 하다. 비동기 콜백이 다중 쓰레드를 이용한 프로그램을 대체할 수 있는 것이 아니라는 것은 인정한다. 하지만, 만약 우리가 그러한(비동기콜백방식의) 디자인 패턴을 유의해서 프로그램을 설계하면, 프로그램을 사용하는 유저 입장에서는 다중쓰레드와 프로그램을 사용하는 것과 비슷한 경험을 하도록 만들 수 있다.
이런 관점에서 Timer 클래스는 아주 유용한 클래스이다, 이 Timer클래스는 "timer"통지 이벤트를 일정한 주기로 발생시킴으로서, 우리가 원하는 함수를 호출하도록 만들 수 있다. 우리는 이 타이머 이벤트를 일정시간동안 실행 가능한 하나의 코드 단위를 전체 로직을 수행하는데 필요한 일부 코드로 생각할 수 있다. 이렇게 플래시 프로그램이 단일쓰레드로 작동되는 덕분에 뮤텍스나 세마포어등을 생각 할 필요가 없어졌다. 하지만 우리는 하나의 비동기 function call에 대해서 너무 오랜 시간동안 수행하지 않도록 조심해야 한다. 단일쓰레드 기반이기 때문에 그럴 경우에는 프로그램 전체가 죽은 것 처럼 보일 수가 있다.
열거형(enum)이 없음
액션 스크립트는 열거형이 존재하지 않는다. (역: enum Typename {a, b, c} 해서 사용할 수 있던 것이 없다. 그 비슷한 것도 없다.) 이건 AS3.0으로 C/C++코를 포팅할 때 조금 더 일을 하게 만든다. 이것은 C/C++에 통달한 사람들에을 꽤 난처하게 만든다. 어떤 사람들은 이런 것을 해결하기 위한 방법을 몇가지 발견하기도 했다. 그 예로 http://www.darronschall.com/weblog/archives/000097.cfm" HREF="http://www.darronschall.com/weblog/archives/000097.cfm" TARGET="_blank">Darron Schall 의 EnumeratedType class 는 enum과 비슷한 기능을 런타임에 할 수 있도록 해주는 하나의 클래스를 제공한다. 이거 좀짱이다. 이 EnumeratedType class 는 간단한 구조로 enum과 관련된 우리들의 문제들을 해결해준다. 하지만 이건 컴파일 타임에 에러를 잡아주지는 못하다 (다른 타입에 할당하거 비교하는 등등의 문제들에 대해서..), 왜냐하면 AS3.0은 모든 타입을 대입할 수 있는 원시자료형(Object)만 우리에게 제공하기 때문이다. (역: 모든 자료형은 Object를 상속받아 만들어졌다. int든 string이든 사실 모두 같은 Object 클래스이다.)
다른 방법은 간단히 클래스를 static을 이용해서 정의하는 방법이다 .
public class MyEnum
{
static public const FIRST:MyEnum = new MyEnum();
static public const SECOND:MyEnum = new MyEnum();
static public const THIRD:MyEnum = new MyEnum();
}
정적 상수로 모두 선언하면 이 클래스는 enum으로 정의한 것과 같이 비교하거나 할당하면서 사용이 가능하다.
가령 이렇게..
public function getValue() : MyEnum
{
return MyEnum.SECOND;
}
이것의 문제는 하나의 enum 타입마다. 클래스를 새로 만들어야 한다는 사실이다. (역: AS3.0은 클래스마다 파일이 하나라서 안그래도 많은 파일이 더 늘어난다.) 하지만 이렇게 만들어두면 자신이 정의한 새로운 클래스 이기 때문에, 대입하거나 비교 하며 사용할 경우에 조금 더 type safe 하게 만들 수 있다.
Public 생성자와 싱글톤
AS3.0에서는 모든 생성자는 public으로 정의되어야 한다. 이것은 ECMAScript4에 규정된 룰이며, 액션스크립트에서는 Private나 Protected 생성자는 사용하지 않는다. 하지만 이 제한은 http://en.wikipedia.org/wiki/Singleton_pattern" HREF="http://en.wikipedia.org/wiki/Singleton_pattern" TARGET="_blank">singleton 클래스를 만드는 보편정인 방법을 사용하지 못하도록 한다는 것을 의미한다. 생성자가 public인 경우에는 누구나 그 클래스의 인스턴스를 만들 수 있기 때문이다. 하지만 약간의 트릭을 이용해서 액션스크립트에서 싱글톤 클래스를 구현할 수 있다. 이전에 작성한 나의 http://blogs.adobe.com/kiwi/2006/05/as3_language_101_for_cc_coders_1.html" HREF="http://blogs.adobe.com/kiwi/2006/05/as3_language_101_for_cc_coders_1.html" TARGET="_blank">AS3/C++ 아티클에서, 패키지외부에 클래스를 정의하는 것에 대해서 이야기 했다. 이 클래스는 파일 내부에서만 액세스가 가능했다 이것을 이용해서 싱글톤을 구현할 수 있다. 아래 나오는 'Singleton.as'가 그 내용을 보여준다.
//Singleton.as
package my.package
{
public class Singleton
{
public function Singleton(blocker:SingletonBlocker)
{
if (blocker == null)
throw new Error("Public construction not allowed. Use getInstance()");
}
public static function getInstance() : Singleton
{
return instance;
}
private var instance:Singleton = new Singleton(new SingletonBlocker());
}
}
// Outside the package, declare the blocker class
class SingletonBlocker
{
}
'SingletonBlocker'클래스가 패키지 외부에 정의되어 있어서, 파일 외부에 있는 다른 클래스가 이 클래스에 접근을 할 수 없다. 또한 public으로 선언된 생성자는 'blocker'파라미터를 필요로 하므로 이 생성자는 사용하면 예외를 발생시킨다. 이 두가지 조합을 이용해 "Singleton"오브젝트가 인스턴스화 되는것을 막을 수 있다. 인스턴스에 접근할 수 있는 방법은 오직 하나 "getInstance()"라는 static 메소드를 이용하는 것 뿐이다.
=================================
=================================
=================================
'ADOBE > ActionScript' 카테고리의 다른 글
플랙스 3.0 레이아웃 컨테이너 (0) | 2011.11.23 |
---|---|
as3.0 캐스팅 (0) | 2011.11.23 |
플래시 AS3.0 특징 몇가지 (0) | 2011.11.15 |
Java에서 쓰는 데이터형(map, array)는 AS3.0에서 어떻게 쓰이나? (0) | 2011.11.14 |
플래시 ActionScript3.0 Array를 사용한 HashMap (0) | 2011.11.14 |