오늘 프로젝트를 정리 하면서 이미지를 jar안에 넣는 작업을 했습니다.

netbeans에서 프로젝트를 하고 있었으므로 jar파일 만드는 것은 알아서 해주지만, 이미지를 넣기

위해서 .class파일들이 모여 있는 곳에 이미지를 옮기고 코드를 수정했습니다.

하지만!!!

동작을 하지 않는 것입니다..

jar파일에 있는 리소스를 가져 오기 위해서 ClassLoader의 getResource 

메소드를 사용해야 합니다.

기존에 직접 파일의 경로로 가서 파일을 직접 읽어 왔던 코드를 jar파일에 있는 것을 

classloader를 통해 읽어 

오는 코드로 변경했는데 동작을 하지 않아서 고생을 하고 원인을 찾아 해매 두시간을 헤매고 있었습니다.

결국 일일이 어디서 문제가 있는지 디버깅 코드를 넣어 가면서 테스트를 하는데 

원인을 밝혀 냈고, 화가 나더라구요...

기존의 코드에 이미지를 얻어 오기 위한 경로와 파일 이름에는 대소 문자를 구분 하지 않았는데 

jar파일 안에 있는 리소스를 얻기 위한 경로 지정해는 대소 문자를 구분 하고 띄어 쓰기는 되지 않는 것을 밝견

했습니다.

결국 문제를 해결했지만... 참.. 찜찜 하네요..

왜이렇게 서로 다르게 만들어서 힘들게 하는 것일 까요...

그리고 jar파일에 이미지를 넣지 않을때와 넣을때..

두 버전을 유지하는 것이 어렵네요.. (이건 제가 아직 잘 몰라서 그런것 같지만..ㅠ)

아무튼 올만에 삽질 좀 했습니다.ㅋ
신고
by danguria 2010.01.05 18:29
아쉬움이 있는데 디버깅 창을 구현 하였습니다.

디버깅 버튼을 누르면 창이 생기고, 디버깅 종료 버튼을 누르면 창이 사라지도록 했습니다.

이 창은 새로 팝업 되는 창이 아니라, canvas가 위치 하는 곳의 영역 일부를 빌려 위치합니다.

실제 구현은 디버깅 버튼이 눌리면, canvas를 빼내고, JSpiltePane에 canvas와 JTable을 담은 

JScrollPane(JTable담고 있음)을 담아서 canvas가 위치 한 곳에 넣어 줌니다.

실제 디버깅 툴의 UI를 보면 도킹이라고 불리는 기술을 사용하는데 저는 그것을 어떻게 구현하는지도 배울 시

간도 부족 하므로 고정된 곳에 넣어 두었습니다.

그래도 전보다 UI가 이뻐지고 있어 만족 하고 있습니다.

상세한 요구 사항을 만족하도록 커스티마이징 하였고 이제 데이터만 넣으면 됩니다.

아참 이 작업을 하기 전에 property를 구현 하다가 말았는데요.. 그건 다음에 설명 드리죠... 아직 미완성이랍니

다.


신고
by danguria 2009.11.13 20:24
createColne 매소드를 모든 심볼에 대해서 구현을 완료 했습니다.

concreteSymbol의 clone함수를 구현하려다 보니 부모 클래스의 멤버 변수도 모두 복사해야 다 던데요..

그부분을 각각의 concreteSymbol에 넣으니까 각 클래스에 중복된 코드가 엄청 많아 졌습니다.

부모클래스에 그 코드를 넣으려고 해도 자식클래스가 어떤 타입인지 모르기 때문에 결국 다시 

하위 클래스에서 다시 복사해야 할 것 같아서 일단 모두 concreteSymbol에서 모두 복사하도록 

하였습니다.

그렇게 하고 모듈 테스트를 위해 여전히 도형의 생성에 대해서만 redo undo 를 체크 했는데 생각하는 

것과 다른 결과가 나왔습니다.

undo를 많이 하고 나서 다른 작업을 할때는 redo할것이 없어야 합니다.( 다른 프로그램이 그렇게 하더

군요..ㅋㅋ) 하지만 그렇게 동하지 않았습니다. 

정상적으로 동작하지 않을때의 UndoRedoManager의 add함수입니다.

/**
     * history의 가장 마지막에 memento를 저장한다.
     * @param memento
     */
    public void add(DMemento memento){
        System.out.println("add memento to manager");
        // 만일 삽입할 위치 뒤에 다른 memento가 있다면 삭제 시킨다.

        // 현재 위치바로 위에 memento가 없을때까지 history의 현재 위치 다음
        // memento를 삭제 한다.        
        for ( int i =0 ;i < history.size(); ++i){//<---- 문제의 지점
history.remove(i);
}
        // 현재 위치를 증가 시키고 거기에 memento를 삽입한다.
        history.add(++currentPos, memento);
        
        System.out.println("Debug : after add history size = " + this.history.size());
        System.out.println("Debug : after add currentPos = " + this.currentPos);
    }


처음에는 어디가 문제인지 모르고 이리 저리 뒤적였지만 문제는 빨간색 부분의 코드였습니다.

저의 생각은 "현재 포지션 다음의 것을 모두 지워라"였지만 

실제 동작방식은 그렇게 되지 못했습니다.

history의 자료 구조가 LinkedList이고 이때 remove를 하면 전체 사이즈가 줄어든다는 것을 생각하지 

못했습니다.  

왜 그런지 알겠죠?( 모르면 ... 저처럼 삽질합니다.ㅋ)

그래서 코드를 다음과 같이 멋지게 수정했습니다.
// 현재 위치바로 위에 memento가 없을때까지 history의 현재 위치 다음
// memento를 삭제 한다.        
      // 와우~~ 멋집니다~~
        while(currentPos + 1 < history.size()){
            history.remove(currentPos + 1);
        }


이제 남은 것은 history에 언제 넣어 줄것인가 입니다. 

painter코드가 좀 지저분한데.... 즉 심볼이 바뀌는 것을 모조리 찾아서 쌍으로 넣어주려고 하니까.. 코

드가 지저분해 질 것 같습니다... 일단 좀 생각해봐야 겠습니다.

신고
by danguria 2009.10.28 22:27

기나긴 고민뒤에 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 |

티스토리 툴바