기존의 타입 안전 열거형 클래스는 각 심볼의 타입을 나타내기 위해서 만들었습니다.
각 심볼의 순서가 필요하지 않기 때문에 클래스에 타입정보만 들어 있었습니다.

이번에 만든 타입 안전 열거형 클래스는 
심볼을 클릭하면 리사이즈 박스가 나오는데, 이때 8개의 리사이즈 박스를 나타내야 합니다.
(LEFT, RIGHT, UP, DOWN, LEFTUP, LEFTDOWN, RIGHTUP, RIGHTDOWN)
8개의 리사이즈 박스 자체만으로는 순서가 필요없지만, 마우스가 어떤 리사이즈 박스를 클릭했는지 알려면 
루프를 돌면서 확인을 해야 하고 그때의 딱 걸릴때의 루프 변수번째가 해당 박스라고 구현 되어 있으므로 
순서를 정해 주어야 했습니다.

다음은 기존의 리사이즈 박스에 대한 Named constant을 쓰고 있는 코드 입니다.

/**
     * 현재 클릭 된 곳이 리사이즈 박스안에 있는 것인가를 알아보는 함수
     * @param mousePoint
     * @return
     */
    public int isReSizeArea( Point mousePoint )

    {

        this.clickedResizeBox = -1;

        for( int i = 0; i < this.numResizeBox; i++)

        {

            if( (this.resizeBoxStartPoints[i].x <= mousePoint.x)

            && (this.resizeBoxStartPoints[i].x + this.resizeBoxWidth >= mousePoint.x)

            && (this.resizeBoxStartPoints[i].y <= mousePoint.y)

            && (this.resizeBoxStartPoints[i].y + this.resizeBoxWidth >= mousePoint.y))

            {

                this.clickedResizeBox = i;

            }

        }

        return this.clickedResizeBox;

    }


심볼에 대한 타입 안전 열거형 클래스에는 순서를 적용 할 수 없었지만,
방법이 없는건 아닙니다.
그래서 새로 만든 순서 기반의 타입 안전 열거 클래스입니다.


public class DResizeBox {
    private final String box;
    private DResizeBox(String box){
        this.box = box;
    }
    @Override
    public String toString(){
        return box;
    }

    public static final DResizeBox LeftUp = new DResizeBox("LeftUp");
    public static final DResizeBox RightUp = new DResizeBox("RightUp");
    public static final DResizeBox LeftDown = new DResizeBox("LeftDown");
    public static final DResizeBox RightDown = new DResizeBox("RightDown");
    public static final DResizeBox Up = new DResizeBox("Up");
    public static final DResizeBox Down = new DResizeBox("Down");
    public static final DResizeBox Right = new DResizeBox("Right");
    public static final DResizeBox Left = new DResizeBox("Left");
    public static final DResizeBox ArrowStart = new DResizeBox("ArrowStart");
    public static final DResizeBox ArrowTarget = new DResizeBox("ArrowTarget");
    public static final DResizeBox ArrowZigzag = new DResizeBox("ArrowZigzag");
    public static final DResizeBox None = new DResizeBox("None");
    private static final DResizeBox PRIVATE_ORDERED_BOX[] = {
        LeftUp, RightUp, RightDown, LeftDown, Up, Right, Down, Left    // None은 넣지 않았음.
    };
    public static final List orderedBox =
            Collections.unmodifiableList(Arrays.asList(PRIVATE_ORDERED_BOX));
}

타입 안전 열거로 정의한 상수는 객체이므로 컬렉션에 넣을 수 있습니다.. 이런식으로 하여 아까전의 코드를 거의 바꾸지 않고 구현 할 수 있었습니다..

매우 좋은것 같다.ㅋㅋ


신고
by danguria 2009.10.23 22:44

기나긴 고민뒤에 Type safe enumeration pattern이라는 것을 발견하고 public static finale int 로 정의된 열거

형 변수들을 정리 하고 있습니다.

C언어에서는 enum구문이 자바에는 없습니다.

 (Enumeration이라는 인터페이스가 있지만 C/C++의 enum과 달리 iterator입니다.)

C에서는

#define TERMINAL 0

#define PROCESS 1

#define LINE 2

...

이런식으로 하던지, 

typedef enum { TERMINAL, PROCESS, LINE, ARROW, ...}symbolType;

이런식으로 사용했습니다.

하지만 자바에서는(물론 자바에서만은 아니겠지만 지금은 자바만 생각하고 있습니다.) 어떻게 해야 할지 몰랐습니다.

그래서 C와 비슷한 방식으로, 클래스안에 값을 직접 적어 넣었습니다.(일종의 하드 코딩을 했습니다.)

Class DSymbol{

public static final int TERMINAL = 0;
public static final int PROCESS = 1;
public static final int LINE = 2;
}


아직까지 이렇게 했을때 큰 문제점을 없었습니다. 있다고 한다하더라고 큰 문제는 없을 것입니다.

하지만!!! 아름다운 코드를 만들기위해서 이렇게 하면 안좋다는 것을 알게 되었습니다.


문제점을 찾아보니 

1. 새로운 상수를 추가 했을 경우 사용자 코드도 다시 컴파일 해야 한다.

2. 새로운 상수가 사용자 코드와 충돌을 일으킬 수 있다.

3. 이런 방식은 출력 가능한 문자열로 바꾸거나, 상수들을 모두 열거할 수 있는 방법을 제공하지 않는다.

그리고 이펙티브 자바책을 보니 "public static final String TERMINAL = "TERMINAL";"로 구현 해도 안된다고 합니다.

이경우 사용자가 TERMINAL과 같은지 비교 하기 위해 "TERMINAL"이라는 문자열을 코드에 직접 넣을 경우, 타이핑

오류를 런타임에 확인 할 수 없고, 디버깅이 어려지기 때문이죠. 

1.번과 2.번과 같은 경우는 내가 짠것을 나만 쓴다면 이런 문제가 없겠지만 이것을 API화 하여 다른 사람이 이것을 쓰

거나 팀프로젝트를 할 경우, 다른 팀원이 나의 클래스를 사용할 경우에 문제가 될 수 있습니다. 

(항상 내코드는 남이 쓸것이다라는 생각을 해야 좋은 코드가 나올 것 같네요..)


이런 문제점을 해결하기 위한 좋은 방법이 있습니다.

Type safe enumeration pattern이라는 것이 있습니다.

가장 간단한 구현은 다음과 같습니다.

public class DSymbolType {

    private final String type;

    private DSymbolType(String type){

        this.type = type;

    }

    public String toString(){

        return type;

    }
    public static final DSymbolType Terminal = new DSymbolType("Terminal");
    public static final DSymbolType Process = new DSymbolType("Process");
    public static final DSymbolType Decision = new DSymbolType("Decision");
}

이 방법의 좋은 점은 다음과 같습니다.


1. static final필드에서 정의된 객체 외에 다른 객체가 생성될 수 없다.

2. 컴파일 시점의 타입 안정정을 제공해준다.

3. 새로운 상수가 추가되더라도 client코드를 변경할 필요가 없다.

4. 상수를 출력가능한 문자열로 문자열로 바꿀수 있다.

1. 같은 경우는 클래스가 final선언이 되어 있지 않지만 생성자가 private으로 선언되어 있으므로, 

이 함수를 상속받더라고 생성자를 호출 할 수 없어서서 결국 상속 받을 수 없다. 따라서 정해진 객체만 참조 할 수 있

는 것이겠죠.

2. 번 은 이 타입안정 열거형을 사용했을 경우, DSymbol의 객체는 NULL아니면 세개 중의 하나겠죠,

 그러므로 잘못된 코드를 작성할 경우 컴파일 타임에 그것을 알게 될 것입니다.

3. 예전에는 새로운 상수가 추가 되면 client 쪽 코드도 변경이 되어야 했지만 이렇게 함으로서 client쪽 코드를 변경

하지 않아도 되게 되었습니다. OCP원칙을 지키게 되었네요.ㅋ

4. 클래스의 toString() 함수를 이용함으로써 상수를 문자열로 제공 할 수 잇는 수단이 생겼습니다.


기본적인 타입 안전 열거형을 업그레이드 하는 버전이 많지만 오늘을 여기 까지 해야 겠네요..


아무튼 저의 코드가 아름다워 지고 있습니다~~


와~~ 만세~~~

신고
by danguria 2009.10.20 23:58
| 1 |