'AS3.0 Cookbook/클래스만들기'에 해당되는 글 2건

  1. 2008.06.06 상속과 구현
  2. 2008.05.31 사용자 정의 클래스 만들기
AS3나 자바등과 같은 OOP언어의 특징은 상속과 구현이다. 상속은 앞서 테스트해본 사용자정의 클래스만들기 부분에서 Test클래스와 같이 부모를 Sprite라는 프레임 없는 무비클립을 상속받았고 Test2클래스는 Test클래스를 상속받았으므로 위의 두성분을 모두 포함하고 있다고 설명하였다. 이처럼 부모의 성질을 이어받는 것이 상속이다.

[ 상속 ]
우선 상속이라는 개념을 살펴보면 그림과 같은 가계도를 갖는다.
사용자 삽입 이미지
그림을 보면 최상위 클래스인 James라는 놈에게서 son1과 son2가 부모의 성질을 받아 만들어졌다.
빨간색 글씨부분은 부모클래스인 James의 성질을 이어받았기 때문에 따로 만들어 주지 않아도 실행이 가능해졌다. 그리고 son1의 경우에는 추가로 2개의 성질을 더 만들어 주어 양손잡이가 되었고 게임도 좋아하게 되었다.
son2의 경우에는 1개의 성질만 추가하였기 때문에 영화를 좋아하는 성질을 갖게되었다.

이처럼 기본기능이 있는 부모클래스를 상속받아 프로젝트에 맞는 부가적인 메서드를 추가로 개발하는것을 상속이라고 생각하면 되겠다.
* 부모에게서 받은 성질중에 고치고자 하고싶은 것은 override하면 된다.
가령 james의 곱슬머리()를 자식클래스에서 기능을 바꾸고자 한다면
override 곱슬머리(){
바꾸고자하는 머리스타일...
}
위처럼 기능을 재정의 하는것이다. (메서드의 재정의 override 참고)

[ 구현 ]
구현은 구조를 만들기 위해서 아주 중요한 부분이 된다.
개발을 하다보면 상속만 가지고는 어느 한계에 마주치게 되고...그 때 아쉽게 생각이 드는 것이 다중 상속이라는 것을 생각하게 된다...하지만 그것은 불가능한 것이기 때문에 Interface라는 것을 만들어 여러형태로 바라볼 수 있게 만드는 것이다. 가령 위그림에서 son1은 James의 아들이다. 하지만 James의 아내가 Jena라면 son1은 Jena의 아들이기도 하다. 하지만 이를 표현하기 위해서 그림과 같은 상속구조에서는
절대 Jena라는 클래스와 son1의 관계를 표현할수 없는 단방향 구조를 갖게된다. OOP의 장점이자 단점인 부분인 것 같다.

그러면 이러한 구성을 Interface로 풀어보자.
사용자 삽입 이미지
James에 관해서는 상속으로 고리가 연결되어있다. 하지만 상속은 단일 상속밖에 되지않으므로 Interface Jena를 만들어 이를 구현하고자 하는 클래스에서 구현(implements)하게 된다. 그러면 Son1과 Son2에는 James의 성질을 갖으면서 Jena의 성질도 포함하게 된다. 중요한 것은 나중에 이들을 부를(호출)때 James의 아들로 호출하여도 되고 Jena의 아들로 호출하여도 이 Son클래스들은 바라보게 된다는 것이다.

만약 이들을 코드로 본다면 다음과 같다.
Package는 생략...
public class Son1 extends James implements Jena
{
//Son1의 생성자(new로 호출했을 때 실행되는 부분)
public function Son1()
{

}
기타 필요한 메서드...
}


Jana의 코드
package
{
 public interface Jena
 {
jena의 설징을 결정할 메서드들 정의
 }
}
Jena는 인터페이스이다. 인터페이스는 항상 public이나 internal로 스코프를 갖게된다.
이들은 이들을 구현할 클래스를 성질을 구분짓기 위해 주로사용되고 인터페이스 내부에는 메서드만 정의해 놓는다. 상세코드는 구형하지않는다.
가령 Jena는 Beauty()이라는 속성만 가지고있다면 아래처럼 코딩한다.
package
{
 public interface Jena
 {
    function Beauty():void

 }
}

이처럼 실행문을 코딩하지 않는다. 이들의 실행문은 이를 받아 구현하는 Son1이나 Son2에서 필요에 따라 작성하면 된다. 단 인터페이스에서 함수가 있다면 해당  함수를 반드시 포함하고있어야한다.
public class Son1 extends James implements Jena
{
  public function Son1()
  {

  }
  function Beauty():void
  {
      필요하다면 기능 구현
  }
}

이렇게 된다면 Son1은 아름답다라는 성질도 갖게되는 것이다. 이 성질은 jena에게서 온것이다.
아쉬운점은 인터페이스에서 상세 구현이 불가능하므로 상속처럼 성질을 이어받으면 호출에서 실행시킬 때 따로 구현할 필요가 없지만 인터페이스는 그때, 그때 상세 코드를 구현하여야 한다..ㅜㅜ;;
하지만 이거라도 되는게 어딘가...

만약 다음과 같은 상황이 있다고 가정하여 보자.
사용자 삽입 이미지

그림을 보면 새를 상속받은 [독수리] , [닭] , [새인형]이라는 클래스가 3개 있다.
이들은 모두 새라고 생각할 수 있다. 이제 이들을 구분지어 보면 누가 "날 수있는 것 모이세요!"하고 외쳤다. 그럼 독수리만 모이게 될것이다. 그럼 "소릴 낼수 있는것 모이세요!"라고 한다면 독수리와 닭이 모일것이며 "새들은 모이세요!"한다면 독수리,닭,새인형 모두 모일 것이다.. 이것은 클래스의 성질을 가지고 구분지을 수 있다는 말이다.

가령 화면에 객체들이 흩어져있다. 이들을 드래그하여 여러개 선택한 다음에 지우기 버튼을 눌러서 지우려고 한다. 그럼 지워질 수 있는 객체는 del()이라는 메서드가 실행되겠지만 지울수 없는 객체는 del()이라는 메서드가 포함되어 있질 않아서 에러를 발생할 것이다. 그럼 del이 있는 객체만 골라서 실행해야하는데
if( 선택된 객체 is Removable ){
    선택된 객체.del()
}
과 같이 객체의 성질을 검사하여 조건문에 의해 선택적으로 실행할 수 있다.
* Removable은 del()을 선언한 인터페이스이다. Removable인터페이스를 implements한 객체는
 반드시 del()이라는 메서드를 구현해 놓아야 하므로 조건식에 만족한다면 del()을 실행시킬 수 있다.






Posted by 버터백통

클래스는 어떠한 프로젝트를 만들때 우리가 필요한 기능들을 묶어 처리하는 하나의 캡슐과도 같은 것이다.
그안에 해당되는 기능/처리에 필요한 많은 명령문과 함수(메서드)를 만들게 된다. 보통 클래스는 public이나 internal로 선언해서 만든다.


사용자 삽입 이미지


그림과 같이 플렉스에서는 새로운 클래스를 만들때 패키지(클래스의 포함경로)와 이름을 정하게 되고 접근제한자를 public/internal중에 한개를 선택하게 되어있다.
superClass에는 상속받을 부모의 클래스를 넣어주면 자동으로 네임스페이스를 클래스 내부에 선언하게 된다.
Interface의 경우에는 구현할 인터페이스의 경로를 설정한다.

사용자 삽입 이미지

그림은 패키지를 com.test라는 경로로 선언하였다. 그러면 com폴더에  test폴더에 저장이 된다.
* 패키지 : 클래스를 그룹화하여 서로 충돌없이 사용하도록 폴더의 구조를 나누는 것이다.
com.test라고 선언한다면 생성하는 클래스는 com이라는 폴더에 test라는 폴더 및에 생성하게 된다.
관행적으로 패키지 이름은 소문자로 한다.
클래스 이름은 관행적으로 첫문자를 대문자로 사용한다. 그리고 Test라고 선언한 클래스이름과 같은 이름(Test.as)으로 파일이 생성하게 된다.
* 클래스이름과 파일명은 항상 같은 이름으로 일치시켜야 한다. 만약 이후 클래스명이나 파일명이 수정되면 둘다 같은 이름으로 일치시키도록 한다.
클래스의 스코프는 전체패키지에서 접근가능하도록 public으로 설정하였고 상속받을 부모는 Sprite(프레임 없는 무비클립)을 상속받았다..
* 상속을 받지 않고 클래스를 생성하면 기본적으로 최상위 클래스인 Object를 상속받게 된다.
실행하면 아래의 그림처럼 클래스가 생성된다.
사용자 삽입 이미지

[ com -> test -> Test.as ]


Test의 소스코드를 보면 아래와 같다.
package com.test
{
 import flash.display.Sprite;
flash라는 폴더에 display라는 폴더에 Sprite 클래스를 임포트하였다.
위의 클래스는 어도비에서 제공하고 플렉스빌더의 sdk에 swc형태로 저장되어있다.
* swc : 라이브러리 프로젝트로 압축된 파일안에 소스코드를 저장해 넣은 클래스집합

 public class Test extends Sprite
Sprite에서 상속을 받았기 때문에 Test클래스는 Sprite의 extends이다

 {
  public function Test()
  {
   super();
  }
이부분이 생성자이다 패키지 어디에선가 이 클래스를 사용하고자 생성시킬때 이 부분이 실행하게 되며
반드시 생성자에는 반환타입이 없다.
super()라는것은 부모의 생성자를 의미한다. 여기서는 Sprite의 생성자를 호출하게 된다.
* parent는 계층구조상 상위의 개념
* super는 상속에서의 상위 개념
 
 }
}

사용자 정의 클래스를 만들어 보았다...이를 다시 상속받는 클래스를 하나 더 만들어보고 비교하면 금방 이해가 가실 것이다.

앞서 만든 Test를 상속받는 클래스 Test2를 com.test2라는 패키지에 만들어 본다.

사용자 삽입 이미지

그림처럼 설정하고 실행하면 아래의 경로에 클래스가 생성되게된다.
사용자 삽입 이미지

소스코드는 아래와 같다
package com.test2
{
 import com.test.Test;

 public class Test2 extends Test
 {
  public function Test2()
  {
   super();
  }
 
 }
}

이 클래스는 Test를 상속받았다 Test클래스는 Sprite를 상속받았으므로 Test2에는 Sprite성분과 Test성분을 모두 포함하고 있다.

* 클래스의 캡슐화 : 클래스를 만들 때 유념해야 할것은 각 메서드의 스코프를 잘 정의하고 내부에서만 사용하는 메서드는 외부에서 접근이 불가능하게 하고 다른 클래스 메서드와의 충돌이나 에러 발생율를 최소한으로 하여 "한 덩어리"로서 자신의 역할만을 충실히 수행하도록 하는 것이 좋다.

Posted by 버터백통