Graphics Programming

표시 계층도에 의존적인 참조의 위험 본문

Season 1/플래시

표시 계층도에 의존적인 참조의 위험

minseoklee 2017. 2. 19. 17:39

표시 객체를 다루다보면 부모 표시 객체를 참조할 일이 생긴다. 비슷한 객체들을 묶어서 관리하기 위해 Sprite 객체 하나를 컨테이너로 쓴다고 치자.



다음은 메인 루프에서 호출되는 Box 클래스의 update 메서드다.


class Box {


public function update():void {

var pivotX:Number = parent.x

var pivotY:Number = parent.y

// do something with (x, y) and (pivotX, pivotY)

}


}


이 메서드는 박스의 부모, 즉 container의 위치를 이용하여 무언가를 갱신한다. 그 외에도 여러 메서드에서 parent 속성을 이용해 컨테이너를 참조한다. 그런데 나중에 편의상 또다시 box와 circle을 따로 묶게 되었다.



컨테이너의 위치, 회전, 크기 변환 등은 그대로 container에 적용하고 box container, circle container의 속성들은 기본값으로 놔둔다. 이제 box들의 parent는 box container, circle들의 parent는 circle container이기 때문에 모든 계산이 어긋나기 시작한다. 프로그램은 런타임 에러로 죽지 않더라도 화면은 엉망진창이 된다.


이걸 고치려면 parent를 썼던 모든 코드를 parent.parent로 바꿔야 한다. 그런데 나중에 계층도가 또 바뀌면? 수정하다 몇 군데는 빼먹으면? 아무리 설계를 신중히 해도, 만드는 도중에 무언가 바뀔 수 있고 대처를 제대로 하지 못하면 미묘한 버그가 발생한다.


위 문제의 간단한 해결책은 '부모'가 컨테이너라고 가정하지 않고, 컨테이너를 반환하는 메서드를 정의하는 것이다.


class Box {


public function update():void {

var container:Sprite = getContainer()

if(container == null){

// deal with exception

}

var pivotX:Number = container.x

var pivotY:Number = container.y

// do something with (x, y) and (pivotX, pivotY)

}


// 혹은 취향에 따라 public function get container():Sprite { return parent }

public function getContainer():Sprite { return parent }


}


코드를 주르륵 써내려가다 보면 이런 기법을 미처 생각하지 못하고 처음처럼 작성하는 경우가 많다. 작성 도중 두 번째 버전처럼 바꿔야 한다고 생각하면서도 나중에 고치지 하다가 까먹기도 한다. 알고 있어도 잘 안 지켜지는, 습관을 들여야 하는 부분이다.

Comments