다음 프로젝트를 MFC를 조금 할 줄 알아야 해서 짬이 있는 틈을 타서 시작 해 버렸
습니다. 원래는 기존에 자바로 구현한 Flower를 그대로 리펙토링 할 예정이었는데, 
C++코딩을 너무 안해서 공부를 다시 해야 하고 MFC프레임웍에 익숙해져야 하기 때문에 Flower를 아주 MFC로 구현 해보려고 합니다.

코드가 나름 커졌기 때문에 한번에 똑같이 구현 할 수는 없으니까 작은 단위로 잘라서 구현해 나갈 생각입니다. 이미 구현을 한 것을 다른 언어와 GUI를 이용하는 거라서 크게 어렵지는 않을 것으로 예상합니다.

아자아자~~ 화이팅!!

일단 MFC의 컨트롤들을 잘 못쓰기 때문에 GUI쪽 말고 로직과 자료구조를 구현하는 것에 일단 초점을 맞추고 있습니다.

오늘은 MFC패턴을 적용하여 큰 틀을 잡는 것만 구현 했습니다.

스윙에서는 controller클래스인 DPainter가 있었지만 MFC자체가 controller가 OS가 담당한다고 해서 위와 같은 모양이 되었습니다.DCanvas가 view에 해당되고(실제 MFC의 뷰클래스입니다.) DSymbolManager가 Model이 됩니다. DSymbol은 도형의 최상위 객체이구요.(DFigure와 DProcedure의 틀만 만들었습니다.) DCanvas와 DSymbolManager가 옵저버패턴이 적용되어야 하는데 그건 내일 해야 겠습니다.

마지막으로 오늘 한 코드의 시퀀스 다이어그램을 올립니다.

신고
by danguria 2010.01.21 18:55
도형 객체를 복사하는 루틴을 "prototype pattern"을 적용하고 있는데,

원래 복사 하는 코드에 비효율적인 부분이 있었습니다.

DFigure라고 하는 추상 클래스는 화살표가 아닌 도형을 나타내는데요..

(단말, 처리, 분기도형 등등이 이에 해당합니다.)

여기에는 이 도형이 화살표로 연결되었을 경우 연결된 도형을 알고 있습니다.

또한, 자신에게 들어오거나, 자신으로 부터 나가는 화살표도 알고 있습니다.(알고 있

다는 표현을 한 이유는 정확하게 composition인지, aggregation인지하는 개념에 아

직 익숙하지 않아서 입니다.)

그런데 복사를 할때 자신 도형에 연결된 도형은 복사 하지 않아야 합니다.

그 이유는 그렇게 하기로 정했기 때문이죠..(다른 비슷한 프로그램들도 그렇게 하더

군요..)

하지만 코드에는 이것 들 마져 모두 복사 하고 있었습니다. 그나마 다행? 인것은 그

렇게 복사된 도형들은 도형 꾸러미에 들어가지 않아서 실제로 보여지지는 않았던 것

입니다. 그래서 제가 이런 현상을 눈치채지 못한 것이구요..

가장 비 효율적인 부분은 Procedure도형이 자신과 연결된 procedure 도형 꾸러미

를 모두 복사 하는 것이었습니다. 이것 역시 화면에 보지 지 않습니다만.. 

만일 원래 procedure코드를 변경하더라고 이것이 반영되지 않을 것이라는 버그를 

안고 있더라구요...

어쨌든 다행이 문제를 파악했고, 그에 대한 해답은 간단하기 때문에 룰루랄라 하면

서 고치고 있습니다^^;
신고
by danguria 2010.01.19 11:11
This is demo videos. If you cannot watch the video clearly, please download the demo files and play it.
< Run the program and debug it>



< Create Figure and change its attributes>



< Copy, paste and cut the figures>




< Change figures' level of layer>



< Procedure>



신고
by danguria 2010.01.04 16:03
코드리뷰를 오늘 했네요..

운영자형에게 시연을 하는데 사소한 버그가 있어서 부끄러웠지만

큰 문제 없이 코드리뷰는 진행되었고, 나름 잘된 것 같습니다.

원래는 팀원 각자가 자신의 코드를 보여주고 시연을 해야 하는데,

GUI파트를 담당한 제가 어찌하다보니까 다 해버리게 되었네요..ㅋㅋ

과제 완료는 계획보다 늦어졌지만, 프로젝트 일정 자체는 일정되로 진행 되어서 

만족하고 있습니다.

마무리하는 차원에서 완료 세미나와 보고서를 써야 하는데 귀차니즘이 또 다가 오고 있네요~~

도와주세요~~~
신고
by danguria 2009.12.28 18:05
너무 오랫만입니다. 한달만이네요. 

시험 기간 전에 과제를 어느정도 마무리 하느라고 정신없이 코딩하고, 

시험치고나서 게을러지는 바람에 늦어 졌습니다.

바로 직전에 제가 썻던 내용을 보니까 프로시저를 구현 하기 직전 까지군요..

프로시저는 현제 잘 동작하고 있습니다. 

이미 컴파일러와 디버거와도 연동되어서 테스트 중에 있습니다.

와~~ 많은 일이 있었군요...

그동안을 간략하게 정리해보아야 겠군요..

1. 프로시저를 구현했습니다.

프로시저로 쓸 InnerFrame을 JFrame을 수정하여서 새로운 InnterFrame을 만들었습니다.

기존의 JInternalFrame은 internalframe을 붙인 패널에는 다른 것이 붙이안아서 직접 서적을 참고하여 

구현하였습니다.

프로시저의 생성은 툴바에 버튼을 통해 생성할 수 있고 삭제는 프레임의 타이틀바에서 삭제 할 수 있습

니다.

타이틀바에 적혀 지는 이름이 곧 프로시저의 이름이 되며, 메뉴바를 통해 변경할 수 잇습니다. 

프로시저 창위에서 만들어지는 도형들은 내부적으로 메인 패널에 있는 것과는 따로 관리 됩니다.

2. 메뉴바의 나머지 이벤트를 구현했습니다.

새로만들기, 열기, 저장, 다른이름으로 저장, 잘라내기, 붙여넣기, 복사등 기본적인 응용 프로그램에서 

제공하는 기능을 구현하였습니다.

저장과 열기는 프로그램에 변경됨에 따라 계속 바뀌고 있는 중인데 

아마 , 앞으로 변경은 되지 않을듯 합니다.

3. Undo, Redo의 대대적인 수정이 있었습니다.

저장과, 불러오기 기능을 구현하면서, 언두, 리두 알고리즘의 문제를 찾았습니다.

연결성을 모두 잃게 되는 문제였습니다.

그래서 다시 구현하였고, 지금은 아무 문제 없이(??) 동작하고 있습니다.

4. Comment 도형을 구현하였습니다.

Comment를 구현하였는데요.. Comment자체는 도형에 화살표가 붙어 있는 모양이기 때문에,

새로운 상속 구조를 만들어야 했습니다. 심볼 의 하위 클래스에 Line과 Figure외에 Comment를 두어 

구현하였습니다.

5. 브레이크 포인트 및 인터프리터, 컴파일러와 연동을 하였습니다.

도형을 우클릭하여 나오는 팝업 메뉴를 이용하여 브레이크 포인트 지정을 구현하였고, 

컴파일러, 인터프리터와의 연동을 위한 작업을 구현 하였습니다. 

현재 컴파일러와 인터프리터와의 연동자체는 잘 작동하고 있지만 

언어 설계와 구현에 대해서는 아직 작업이 남아 있습니다.




기억을 더듬어서 적어봤는데 아쉽군요.. 

마무리로 멋진 UI화면을 보내 드립니다~~
신고
by danguria 2009.12.22 23:01
오늘까지 속성창에 대해서 이벤트 처리를 완료 했습니다.

기본적으로 도형을 클릭하면 속성창에 그 값이 바로 반영되고 속성창의 값을 변경시키면 선택된 모든 도형의 

값을 모두 변경 시키게 했습니다.

여러개를 선택하게 되면 같은 값을 가질 경우만 값을 나타내고 다른 경우는 초기 값을 넣어 주었습니다.

이때 조금 문제가 있었는데요..

두 도형의 값이 다르면, 속성창에 초기 값을 넣어 주는데, 이것 또한 이벤트가 발행해서 두 도형 모두 초기 값으

로 값이 변경 되는 것이 었습니다.

그래서 생각한 방법이 도형을 선택하게 되면 일단 이벤트 리스너를 제거 했다가 초기화 후 다시 이벤트 리스너

를 동작 하도록 하였습니다.

추가 적으로 한 것이 있는데요.. 프로시저를 구현할 내부 창이 기존 창과 동작 모습이 어색했는데,

이를 해결했습니다.

결과만 간단히 말하자면, JLayeredPane을 잘 이용하니까 되더군요...

내일 드디더 프로시저를 구현할 것 입니다. 내일 아무일도 하지 않기 때문에 풀로 작업 할 수 있어서 내일 마지

는 것이 목표 입니다.


신고
by danguria 2009.11.20 01:51
드디어 올것이 왔군요..

지금까지 프로시저를 생각하지 않고 구현하고 있었습니다. 큰 문제가 없을 것이라고 생각 했지만

문제가 있긴하군요..

현재는 심볼 매니저와 캔버스가 하나의 쌍으로 있어서 그것이 뷰와 모델의 관계를 했었는데

이제 함수가 들어오면서 부터 여러개의 심볼 매니저와 캔버스가 있어야 합니다.

먼저 painter(controller)는 심볼매니져와 캔버스의 쌍을 관리 하고 있어야 합니다.

즉, 사용자가 활성화 한 캔버스에 대한 심볼 매니저가 적정하게 동작 해야 합니다.

그리고, 프로시저 심볼을 디자인 해야 합니다.

프로시저라는 심볼은 내부적으로 나의 심볼 매니저를 알고 있어야 합니다. 왜냐하면 심볼 매니저로 부터 해당 

프로시저의 시작 심볼을 가져 와야 하니까요(컴파일러가 추적할 수 있어야 함니다.)

일단 설계를 해보았습니다.

기본적으로 MVC패턴입니다.

symMng가 모델, canva가 뷰, painter가 컨트롤러 입니다.

각각의 참조가 MVC과 약간 달르고 아직 변경의 여지가 있기 때문에 association로 표현 했습니다.

페인터와 캔버스가 symMng의 데이터, 즉 심볼들의 변화에 따라서 상태와 겉모습이 바뀌어야 합니다.

캔버스는 심볼의 그림을 그려 주어야 하므로 draw옵저버가 되고,
페인터는 심볼이 선택됨에 따라 해당 심볼의 속성을 각 컨트롤에 반영해야 합니다 (이부분이 뷰에 대당하는 것 같은데 컨트롤이 painter에서 구현 되어 있습니다...)그래서 속성 옵저버가 되고, 프로시저가 생성되고 소멸됨에 따라 현재 캔버스와 심볼매니저의 쌍을 교체 해야 하므로 프로시저 옵저버가 필요합니다.
여기서는 표현 되어 있지않지만 사용자에 의해 현재 캔버스와 심볼매니저의 쌍을 교체 해주어야 하는데 이것은 페인터가 내부적으로 해결 할 수 있을 것 같습니다.

심볼 매니저는 만들어진 모든 옵저버를 받아드리고 notify하는 subject를 구현 하도록 하였습니다.


신고
by danguria 2009.11.18 00:14
조금 게을러지긴 했지만 얼추 마무리를 했습니다.

마지막까지 고생을 시킨 것이 있었는데요..

pallet이 생각했던데로 디자인이 되지 않고 자기 멋대로 행동 하더라구요... 

아무튼 이래저래 해서 안정시켜 두었는데 GUI layout을 구성할때 공부가 부족했던것 같습니다.

얕잡아본것이죠...

아무튼 다음주 부터는 controller와 연동하는 것인데 그에 앞서 전체적인 설계를 다시 하면서 연동해야 겠습니다.

함수기능을 염두에 두고 구현 해야 하죠...


신고
by danguria 2009.11.16 00:58
아쉬움이 있는데 디버깅 창을 구현 하였습니다.

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

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

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

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

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

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

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

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

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

다.


신고
by danguria 2009.11.13 20:24
오랜만에 Flower 프로젝트를 했습니다.

요즘.. 개을러 지기도 했고, 학교 과제도 많았기 때문에 조금 지체 되었습니다.

아무튼 이번달 구현해야 하는 것은 크게 몇가지가 있습니다.

GUI 껍데기(?!)구현하기

기존에 구현된 기능을 GUI와 붙이기

위의 둘을 MVC 패턴을 이용하여 구현하기

순서도 그리는 모듈 미완성부분 완성하기

컴파일러 모듈과 통신을 위한 설계 회의 하기

이번주는 GUI껍데기와 기존의 순서도 모듈을 붙이는 것까지가 목표입니다.

오늘은 Property pallet부분과 debugging panel을 제외한 부분을 모두 완성 시켰습니다.

나름 이쁘게 나온 것 같아서 좋습니다.ㅋ


신고
by danguria 2009.11.10 21:44
MVC
Undo Redo기능을 구현하고 painter 클래스의 복잡성이 너무 커지고, 전체적인 구조가 흔들려서 

과감히 리팩토링을 하고 있습니다. 일단 MVC모델을 기반으로 하려고 하고 있고(전에도 그랬었지만 view와 controller가 섞여 있었습니다.) 그 첫단계로 UI(view)를 설계하고 있습니다.

함수 기능과, 디버깅 기능을 추가 고려 하여 완벽한 버전의 UI를 만들고 있습니다.

아마 다음주 중간쯤에는 완성될 것 같네요.. 

이번주말은 컴파일러 숙제가 있어서 많이 코딩을 하지는 못할 것 같습니다.
신고
by danguria 2009.11.08 00:29
일단 마무리를 지어야 할 것 같습니다.

구현은 다 했지만 테스트를 하기 위한 환경이 갖추어 지지 않았네요..

painter 쪽, 즉, 컨트롤러 쪽이 리팩토링을 해야 할 시기가 온것 같습니다..

오늘의 코딩 시나리오를 알려 드리죠.ㅋㅋ 

redo undo가 구현이 완료 되어서 history에 언제 넣는지 결정하고 소스의 해당부분에 코드를 집어

 넣으려고 했습니다. painter가 redoUndomanager와 symbolManager를 모두 갖고 있었기 때문에 

코드는 redoUndoManager.add(symbolManager.createMemento()); 였습니다.

하지만, 굳이 painter가 redoUndoManager를 가질 필요가 없다고 생각하여 symbolManager가 

redoUndoManager를 갖고 내부적으로 symbol들의 상태를 저장해야될 필요가 있을때 

redoUndoManager의 add함수를 호출 하는 식으로 루틴을 변경했습니다. 하지만, 이렇게 하면

세밀한 history를 저장하지 못하고, 불필요한 history를 저장할 수 밖에 없는 상화이 오므로 다시 원래 

대로 복구 했습니다. 이렇게 하는데 또다른 추가 사항이 생겼습니다.

속성창을 통해서 속성을 변경하게 된다면, 이것도 history에 저장해햐 하는데 propertyManager는 

undoManager와 symbolManger와 painter를 모르기 때문에 속성이 바뀐것에 대한 history저장을 

할 수 없다는 것을 알게 되었습니다. 물론, property manager가 위의 것들을 알면 되지만 이렇게 되면 

너우 서로 의존도가 심하기 때문에 결굴 모든것을 중단하고 painter, symbolManger, 

redoundoManager, propertyManager, 간의 중재를 해주는 무언가를 두어 리팩토링을 해야 겠다는 

결론을 내렸습니다. 어떻게 할까 생각 하던중, 그렇다면, painter에 있는 버튼 그룹도 추가하여 서로 중

재해주면 되겠다는 생각을 추가하게 되었고, 더이상 머리가 복잡해지고, 이미 집중력의 한계와 늦은 시

간이 되었기 때문에 마무리를 하게 되었습니다.

헥헥헥.....

일단 쉬었다가 좋은 정신력으로 제대로 된 설계를 해야 하겠습니다.

그럼 안녕히 주무세요....~~


신고
by danguria 2009.10.29 23:12
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
Deep Copy... 과연 많이 해도 좋을지 모르겠습니다.

오전까지의 구현에서 얕은 복사를 하고 있었기 때문에 Undo, Redo를 해도 

제대로 동작 하지 않았습니다.

그래서 UndoRedoManager가 관리 하는 history에 SymbolManager가 만들어 낸 memento를 

넣을때 SymbolManager가 갖고 있는 멤버변수를 모두 Deep copy해야 한다는 결론이 나왔습니다.

일단, SymbolManager가 갖고 있는 멤버 변수들은 모두 colloection들로 모두 레퍼런스 변수를 

담고 있습니다.

이 레퍼런스 변수는 DSymbol이라는 놈들인데요..(실제로는 DSymbol을 상속받은 것들이겠죠)

 그림에 드려질 도형들입니다.

문제는 이 DSymbol안에 있는 것들도 상당한 양의 레퍼런스 변수를 담고 있어서 Deep Copy를 하면 

시간과 메모리가 많이 들것 같습니다.

문제는 그것만이 아니더군요..

UndoRedoManager가 Undo, Redo 함수를 통해 memento를 리턴할때도 Deep Copy 를 해서 그것을 넘겨주어

야 했습니다.

그렇게 하지 않으면 SymbolManager가 그 값을 변경하면 history의 memento도 갖이 변경이

 되니까요..

두가지 상황에서 많은 Deep copy가 일어 나고 있습니다.

마땅한 다른 해결책이 없어서 그대로 쓰지만 잘 봐야 할 점인 것 같습니다.

일단 오늘은, 특정 도형에 대해서만 Clone(Deep copy를 이용) 을 구현했습니다.

모두 구현 하고 최종 테스트는 내일이 될 것같습니다.

와우~~ 수고 했어!!!ㅋ


신고
by danguria 2009.10.27 21:38
어제 까지 시험이라서 설계만 하고 어제 저녁 부터 구현을 시작했습니다.

memento 패턴을 이용하여 설계하였고, 

추가로 UndoRedoManager를 두어 여러개의 memento를 관리하도록 했습니다.

구현을 어느정도 마친뒤에 테스트를 해보았습니다.

memento를 저장해야 하는 시점을 아직 확정하지 못해서 일단 심볼들이 캔버스에 생성되는 시점만 

정하고 제대로 동작하는지 디버깅 출력문을 두었습니다.

몇개의 오류를 잡았지만 생각 못한게 있었네요..

바로바로바로 memento에 들어가는 것들이 모두 referrence 타입이라는 것입니다.ㅋ

메멘토를 만들때 저장할 것들이 reference 타입이므로 그대로 대입하면 ( var = imRefType; )

 memento가 저장되는 것이 아니라 포인터만 늘어가게 되는 것이죠...

코드를 짜면서 생각해보았지만 혹시..하면서 일단 복사하지 않고 대입을 해보았는데(속도를 위해서..)

 안되더군요..

일단 학교를 가야 하므로 여기까지 해야 겠습니다.
신고
by danguria 2009.10.27 12:07
UndoRedo를 구현하기 위해서 Memento 패턴을 사용하고 있습니다.

Command패턴과 섞어서 쓰는 것이 맞는지 모르겠지만 일단 Memento만 이용하고 있습니다.

UndoRedo했을때 대상이 되는 상태를 심볼매니저에 있는 멤버변수들로 했습니다.

심볼매니저의 멤버변수에는 현재 캔버스에 그려진 심볼들, 사용자가 선택한 심볼들, 라인을 가질 후보 Figure

이 있습니다.

DSymbolManager가 Originator가 되고,

DMemento가 memento가 됩니다.

reodo undo를 하기 위해서 memento를 많이 갖고 있어야 하므로, 그것을 관리하는 UndoRedoManager를 만
들어 관리하도록 하였습니다.

클라이언트에 해당하는 painter클래스에 DSymbolManager와 UndoRedoManager를 가지고 redo undo를 

수행 하도록 했습니다.

내일 정보보호론 시험이 있는 관계로 설계만 하고 마쳐야 할 것 같습니다.


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

이번에 만든 타입 안전 열거형 클래스는 
심볼을 클릭하면 리사이즈 박스가 나오는데, 이때 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 |