move, resize, draw 등의 작업은 prepare, keep, finish로 단계가 모두 동일하게 진행된다. 때문에 다형성 객체로 생각을 해야한다.
→ n개의 도형에 일관되게 들어가는 메소드를 일반화시키는 것이다.
Transform 클래스를 만들고 그것을 상속 받는 하위 클래스들을 만든다. (Resizer, Translator)
공통적인 코드는 Transform 클래스가 가지고 있다. 패널에서 mouse event가 발생하면 어떤 이벤트인지를 판단해서 알맞은 생성자를 생성할 수 있도록 프로그램을 설계한다.
Transform tf = new ?();
tf.prepareTransforming();
tf.keepTransforming();
tf.finishTransforming();
// 메소드 일반화
도형을 활용한 변환 작업은 drawer, mover, resizer, rotator 등이 있다. 해당 작업은 모두 마우스 이벤트 중 pressed, dragged, released의 연속 이벤트 실행으로 이루어진다. 모든 도형 객체들과 연계되는 작업이기 때문에 별도의 클래스를 생성하여 연계성을 처리했다.
최종적으로 DrawingPanel 안에 Transformer 객체를 하나 넣어놓고 어떤 user event가 발생하는지에 따라서 drawer, mover, resizer, rotator 등의 작업이 알맞게 실행될 수 있도록 설계됐다.
도형의 변환은 affinetransform을 활용하여 처리했다. 움직인 좌표에 대한 정보(matrix)는 affinetransform 내에 실시간으로 계산되어서 저장된다.
배율로 계산한다. selectedAnchor의 대각선에 있는 앵커를 찾아낸다. (resizeAnchor)
x, y 축에서 양의 방향으로 움직일 때와 음의 방향으로 움직일 때의 경우를 나눠서 생각해야한다.
음의 방향으로 움직일 때는 원점이 움직이는 문제점이 존재한다. 도형이 resize될 때는 항상 오른쪽 아래로만 커지기 때문에 크기를 늘린 후 도형의 원점을 위로 움직여줘야 한다.
// resizeAnchor의 원점 계산
public Point2D getResizeAnchorPoint(int x, int y) {
switch (this.eSelectedAnchors) {
case eNW:
this.eResizeAnchor = EAnchors.eSE;
break;
case eWW:
this.eResizeAnchor = EAnchors.eEE;
break;
case eSW:
this.eResizeAnchor = EAnchors.eNE;
break;
case eSS:
this.eResizeAnchor = EAnchors.eNN;
break;
case eSE:
this.eResizeAnchor = EAnchors.eNW;
break;
case eEE:
this.eResizeAnchor = EAnchors.eWW;
break;
case eNE:
this.eResizeAnchor = EAnchors.eSW;
break;
case eNN:
this.eResizeAnchor = EAnchors.eSS;
break;
default:
break;
}
Point2D point = new Point2D.Double(
anchors[eResizeAnchor.ordinal()].getCenterX(),
anchors[eResizeAnchor.ordinal()].getCenterY()
);
return point;
}
프로그램 설계 시에 고려해야할 점
→ modularity 향상
하나의 객체 안에 있는 것들은 연결성이 커야하고, 두개의 객체로 나눈 것들은 서로 연결성이 작아야한다.
현재 디자인은 transformer가 별도의 객체로 생성되어 있는데 다른 객체들과 연결성이 매우 크다는 문제점이 존재한다.