액션스크립트 2.0에서의 클래스 – 객체지향 프로그래밍
액션스크립트 2.0 에서의 클래스
액션스크립트 2.0이 발표되면서 가장 큰 변화를 겪은 부분이 바로 이 클래스와 관련한 부분일 것이다. 기본적으로 액션스크립트가 객체지향프로그래밍 언어로서의 특징을 갖기 위해 가장 기본이 되는 것이 바로 클래스인데, 기존의 액션스크립트의 클래스는 뭔가 부족한 감이 많이 있었고, 이에 그 부족한 점들을 채원 넣기 위해 많은 변화가 있었다. 지금부터 이 클래스에 대해 차근차근 알아봄으로써, 어떻게 바뀌었고, 또 어떻게 활용할 지 알아보자.
프로그래밍이란 어떤 문제가 주어졌을 때, 컴퓨터를 이용하여 그 문제를 풀기 위해 컴퓨터에게 명령하는 명령어의 집합을 작성하는 것이라고 볼 수 있다. 이런 프로그래밍을 위한 방법에는 여러가지가 있고, 그 각각의 기법에 따라 여러 이름들을 붙일 수 있다. 그 중 하나가 바로 객체지향프로그래밍이다. 한편 프로그래밍 언어에 따라 이런 기법들 중 어떤 것은 가능하고 어떤 것은 가능하지 않다라는 구분이 생길 수 있다. 따라서 객체지향프로그래밍 언어라고 말하면, 프로그래밍 언어들 중에서 객체지향프로그래밍을 할 수 있도록 지원하는 언어라고 할 수 있다.
객체지향 프로그래밍이 세상에서 득세를 하기 전에는 절차식 프로그래밍이라는 프로그래밍 기법을 이용해 왔었다. 절차식 프로그래밍이란 기본적으로 하나의 메인 함수가 있어서, 프로그램이 시작 되면 이 메인 함수에 있는 명령어들이 위에서부터 순서대로 한 줄씩 순차적으로 처리되는 기법이다. 종종 코드의 재사용을 위해, 몇 개의 관련 코드들을 묶어서 함수로 선언해서 메인 함수에서 불러 쓰기도 했다. 이런 절차식 프로그래밍 기법은 기본적으로 메인 함수가 전체 프로그램의 수행을 책임지고 있었고, 그러다보니 자연스럽게 이 메인 함수의 덩치가 아주 커질 수 밖에 없게 되었다. 거기다 다양한 요구사항이나, 사용자들의 입력, 상황에 맞춘 모든 경우에 대해 프로그래밍을 하다 보면, 메인 함수의 코드는 점점 더 복잡해지고, 유지 보수의 측면에서도 점점 힘들게 되었다. 게다가, 점점 문제는 복잡해지고, 프로그래머의 능력은 한계가 있으니, 한 명의 프로그래머가 전체 프로그램을 작성하는 일은 불가능에 가깝게 되어 버렸다. 결국 여러 프로그래머가 동시에 하나의 문제를 해결하기 위한 프로그램을 작성할 수 밖에 없게 되었는데, 여기서 문제가 발생한다. 두 명의 프로그래머가 문제 해결에 뛰어든다고 해서 문제가 두 배 빠르게 해결 되지는 않더라는 것이다. 이런 현상들을 소프트웨어의 위기(software crisis)라고 불렀는데, 이런 와중에 코드의 재사용과 복잡한 문제의 단순화를 표방하면서 나타난 기법이 있었으니, 그것이 바로 객체지향프로그래밍 기법이었다.
그럼 객체지향프로그래밍이란 무엇인가? 1993년 Alan Kay는 자신의 논문에서 객체지향 프로그래밍의 기본 개념에 대해 다음과 같이 정리했었다. 조금 어렵겠지만, 천천히 음미하듯이 읽어보도록 하자.
- 모든 것은 객체다.
- 프로그램의 모든 작업은 객체들에 의해 이루어진다. 이 객체들은 서로 메시지를 주고 받을 수 있다. 여기서 메시지는 다른 객체에게 어떤 일을 해 달라고 요청하는 것으로, 작업에 필요한 정보가 있으면 같이 넘겨줄 수도 있다.
- 각각의 객체는 다른 객체들로 이루어진 자신만의 저장 공간을 가지고 있다.
- 모든 객체는 클래스의 인스턴스이다. 여기서 클래스는, 간단히 말하자면, 비슷한 것들을 모아 놓은 것이라 할 수 있다.
- 클래스는 어떤 객체와 관련이 있는 행위들을 모아 놓은 저장소라고 할 수 있다. 이 말은 다시 말하면, 같은 클래스의 인스턴스인 모든 객체들은 같은 작업을 수행할 수 있다는 것이다.
- 클래스는 상속 계틍이라 불리는, 하나의 루트 노드를 가지는 트리 구조를 형성한다. 이 트리 구조에서 어떤 클래스는 그 부모에 해당하는 클래스의 인스턴스가 가지는 메모리나 수행하는 작업들을 그대로 물려받는다. 즉 부모 클래스의 인스턴스의 능력을 그대로 물려 받는다는 말이 된다.
뭔가 느껴지는 것이 있는가? 객체지향 프로그래밍에서 가장 중요한 개념이 바로 클래스라는 점만 느껴도 절반은 이해한 것이다. 객체지향프로그래밍은 세상의 모든 현상이나 일들을 객체의 상호 작용으로 파악하며, 그 철학을 프로그래밍 기법으로 옮겨 놓은 것이다. 어떤 문제가 주어지면, 그 문제를 구성하고 있는 인자들의 상호 작용을 파악하여, 문제 해결을 시도한다. 그러므로, 객체지향프로그래밍에서 중요한 점은, 문제를 구성하고 있는 각각의 인자들을 제대로 파악해 내는 것이라고 할 수 있다. 문제를 구성하는 각각의 인자들이 파악되면, 그 인자들을 각각 독립된 객체로 구현하여, 그 객체들의 상호 작용을 통하여 문제를 해결할 수 있는 것이다. 이렇게 문제 해결을 하게 되면 전체 문제가 아무리 복잡하더라도, 개별 프로그래머들은 자신이 맡은 객체 단위에만 접근하면 되므로, 문제의 복잡도가 매우 떨어지게 되는 것이다. 또한 이런 객체들은 다른 객체들과는 독립적으로 구현되므로, 주고 받는 메시지만 미리 정의해 놓으면 얼마든지 다른 문제의 해결을 위해서도 재사용될 수 있었다.
뭔가 복잡하게 이야기가 진행되었는데, 여기서 더 나아가는 내용은 이 글의 목적을 넘어서게 되므로 참고도서 한 권을 소개하는 것으로 마무리 하려고 한다. Timothy budd라는 사람이 쓴 An Introduction to Object-Oriented Programming이란 책으로 지금 third edition까지 나온 것으로 안다.
그럼 이제 클래스에 대해 살펴보자. 클래스란 건축으로 말하자면, 일종의 설계 도면과 같은 것으로서 ,액션스크립트에 정의되어 있는 데이터 타입 외에 사용자가 자신만의 데이터 타입을 만들고자 할 때 그 데이터 타입에 대한 정의를 기술해 놓은 것이다. 즉 사용자 정의 데이터 타입에 대한 일종의 설계 도면인 것이다. 액션스크립트 2.0에서는 이 설계 도면을 작성하는 방법이 바뀌었는데, class라는 키워드를 이용하여 클래스를 작성한다. 문법은 다음과 같다.
class Classname {
// class definitions
}
객체지향프로그래밍의 관습 상 클래스 이름은 대문자로 시작하는 것이 좋다. 클래스의 모든 속성이나 메소드는 클래스 이름 뒤에 나오는 중괄호 안에 들어가 있어야 한다. 액션스크립트 2.0에서 클래스 정의는 외부 .as 파일에 저장되어야 하고, 그 파일의 이름은 클래스의 이름과 같아야 한다. 예를 들어 Box라는 클래스를 작성한다고 하면, 다음과 같이 정의할 수 있고, Box.as라는 이름의 파일에 저장되어야 한다.
Class Box {
}
이렇게 클래스를 선언하면, 그 중괄호 안에 다음과 같은 것들을 추가해 넣을 수 있다.
- 생성자: 클래스의 인스턴스를 초기화 하는 데 이용된다.
- 변수: 클래스의 속성이 된다.
- 함수: 클래스의 메소드가 된다.
- #include 명령문: 속성, 메소드, 생성자의 정의를 담고 있는 파일을 추가할 수 있다.
- 플래시 MX 2004의 컴포넌트에서 이용되는 메타데이터 태그
- 주석
이 이외의 어떤 것도 추가할 수 없다. 예를 들면 다음과 같은 스크립트는 에러를 발생한다.
class Box {
if (100 == 10 * 10) {
trace(”One hundred is ten times ten”);
}
}
왜냐하면, if문은 클래스 정의 부분에 직접 들어가지 못하기 때문이다 .만약 위의 if문을 수행시키고자 한다면, 클래스의 함수로 정의해 놓고 클래스의 생성자 안에서 그 함수를 호출하도록 다음과 같이 고칠 수 있다.
class Box {
public function Box() {
init();
}
public static function init():Void {
if (100 == 10 * 10) {
trace(”One hundred is ten times ten”);
}
}
}
위 스크립트를 하나씩 살펴보자. 제일 먼저 만나는 것은 public이라는 접근 한정자이다. 이 접근 한정자에는 public과 private이 있는데, 이에 대한 자세한 사항은 다음에 알아보기로 하고, 일단 public이라고 설정하면, 외부의 누구나 이 메소드를 호출할 수 있다는 뜻이라는 것만 알아두고 넘어가자. 한 가지 덧붙인다면, private이라고 설정하면 외부에서 그 메소드를 호출할 수 없다는 뜻이 되고, 생성자가 private인 경우에는 외부에서 new연산자로 그 클래스의 인스턴스를 생성할 수 없다는 뜻이 된다. 즉, 생성자를 public으로 해 줘야 외부에서 그 클래스의 인스턴스를 생성할 수 있다는 말이다. public 뒤에 나오는 내용은 일반적인 함수의 정의와 별반 다를 바 없어 보인다. 이 생성자의 내부에서는 다른 메소드인 init()이라는 메소드를 호출한다. 그러면 이제, init() 메소드를 살펴보자. 이 메소드도 접근 한정자는 public으로 되어 있다. public뒤에 따라 오는 키워드로 static이라는 키워드가 있다. 이 키워드의 의미는 이 메소드가 인스턴스 메소드가 아니라 클래스 메소드라는 뜻이 된다. 클래스 메소드와 인스턴스 메소드의 차이는 나중에 좀 더 자세히 설명하겠다. 우선 간략히 설명해 보면, 인스턴스 메소드란 먼저 그 클래스의 인스턴스를 생성해야 호출할 수 있는 메소드이고, 클래스 메소드는 인스턴스를 생성하지 않아도 클래스에서 호출할 수 있는 메소드를 말한다. 즉, 위에서 생성자 안에서 Box라는 클래스의 인스턴스를 생성하지 않고서도 init()이라는 메소드를 호출할 수 있었던 이유는 init()이 static 키워드에 의해 클래스 메소드로 선언되었기 때문이다. 다음 뒤이어 나오는 내용은 일반 함수를 정의하는 문법과 다를 바 없다. 여기서 한 가지만 더 이야기 하자면, init()이라는 메소드는 Void 타입을 리턴한다고 되어 있는데, 생성자에는 아무런 리턴 타입이 명시되어 있지 않다. 타입 검사를 위해서는 데이터 타입을 명시하라고 그렇게 얘기했는데, 실수한 것일까? 아니다. 원래 생성자는 리턴 타입을 명시하지 않는 것이 올바른 문법을 따르는 것이다. 기억해 두자.
이제 조금 감이 잡히는가? 잡히지 않는다고 속상해 하지 말자. 어디까지나 위의 설명은 그냥 간단히 예제 코드를 설명한 문장일 뿐이다. 이해 안되는 부분들은 뒤쪽에서 하나씩 설명할 때 이해하면 된다. 이 클래스에 대한 글을 모두 읽고 난 후 위의 예제 스크립트를 설명한 글을 읽어보면 너무 간략하게 설명했구나 하는 것을 깨닫게 될 것이다. 그러니 계속해서 다음으로 넘어가도록 하자.
위에 간략히 생성자에 대해 언급했는데, 좀 더 자세히 생성자에 대해 이야기 해 보자. 생성자란 일반적으로 얘기하자면, 클래스의 인스턴스를 처음 생성할 때 그 클래스의 인스턴스를 초기화 해 주는 특별한 메소드이다. 그러므로 이 생성자는 처음에 한번 호출되고 나면 그 이후에는 또 다른 인스턴스를 생성할 때가 아니면 호출되지 않는다. 일반적으로, 새로운 클래스를 만들 경우, 일단은 빈 생성자를 하나 만들어 두고, 후에 클래스에 속성들이 추가될 때마다 그 속성을 초기화 하는 코드를 생성자 내부에 넣어주면 편하다. 위의 예제 스크립트에서 init()관련 내용들을 모두 삭제하고 다음과 같은 스크립트를 작성하자.
class Box {
public function Box() {
trace(”in the constructor of the Box class”);
}
}
이 정의를 Box.as라는 외부 파일로 저장해 두고, 새 플래시 문서를 작성하여 이 클래스 타입을 데이터 타입으로 가지는 변수를 다음과 같이 하나 만들어 실행해 보자.
var b:Box = new Box();
그러면 결과 창에 in the constructor of the Box class라는 문구가 보일 것이다. 이것은 Box 클래스의 인스턴스 b를 생성할 때, 생성자가 호출되었기 때문이다. 만약 클래스를 정의할 때 생성자를 정의하지 않으면 어떻게 될까? 이런 경우에는 컴파일러가 빈 생성자를 임의로 만들어서 컴파일 하므로, 걱정하지 말자.
생성자에 대한 다른 이야기들은 클래스의 속성과 메소드와 연관이 있으므로, 그에 대한 이야기를 먼저 한 후에 하는 것이 나을 것 같다. 그러므로 일단 속성과 메소드에 대한 이야기를 마칠 때까지 생성자에 대한 이야기는 여기까지만 하기로 하고, 속성과 메소드에 대해 알아본 후에 다시 생성자에 대한 주제로 돌아와 이야기를 계속 하기로 하자.
참고 문헌
- An Introduction to Object-Oriented programming 2dn eidtion, Timothy budd, Addison Wesley
- Essential ActionScript 2.0, Colin Moock, O’Reilly