Command (커맨드 패턴)

|

Command Pattern

실행하고 싶은 일을 메소드를 호출하는 방법대신 명령 클래스를 만들어 관리한다.
이력을 관리하고 싶은 경우엔 인스턴스 집합을 관리하면 된다.
이렇게 하면 Undo, Redo 같은 기능을 구현하는 것이 가능하다.

예 : 그림판, 텍스트 편집기

Command Interface
기본적인 커맨드 인터페이스는 execute() 메서드 하나만 가지고 있다.

public interface Command {
    void execute();
}

Command Interface의 구현체 DrawCommand
다양한 커맨드를 구현하며 그릴 대상(Canvas)과 위치를 가지고 있다.

public class DrawCommand implements Command {

    protected Drawable drawable;

    private Point position;

    public DrawCommand(Drawable drawable, Point position) {
        this.drawable = drawable;
        this.position = position;
    }

    @Override
    public void execute() {
        drawable.draw(position.x, position.y);
    }
}

Command Interface의 구현체 MacroCommand
redo나 undo를 구현하기 위하여 존재한다. 커맨드 구현 객체를 스택에 추가하고
한번에 execute 하고 stack을 pop() 또는 push()하여 redo, undo를 구현한다.

public class MacroCommand implements Command {

    // undo를 위하여 스택을 사용함
    private Stack commands = new Stack();

    @Override
    public void execute() {
        Iterator it = commands.iterator();

        while (((Iterator) it).hasNext()) {
            ((Command) it.next()).execute();
        }
    }

    public void append(Command cmd) {
        if (cmd != this) {
            commands.push(cmd);
        }
    }

    public void undo() {
        if (!commands.empty()) {
            commands.pop();
        }
    }

    public void clear() {
        commands.clear();
    }
}

그림그리기 대상 인터페이스
캔버스에서 제공할 수 있는 메서드들을 제공한다.

public interface Drawable {
    void drawOval(int x, int y);
    void drawRect(int x, int y);
}

그림그리기 대상을 구현한 캔버스
타원과 사각형을 그리는 방법을 구현한다.

public class DrawCanvas extends Canvas implements Drawable {

    private Color color = Color.red;

    private int radius = 6;

    public DrawCanvas(int width, int height) {
        setSize(width, height);
        setBackground(Color.white);
    }

    @Override
    public void drawOval(int x, int y) {
        Graphics g = getGraphics();
        g.setColor(color);
        g.fillOval(x - radius, y - radius, radius * 2, radius * 2);
    }

    @Override
    public void drawRect(int x, int y) {
        Graphics g = getGraphics();
        g.setColor(color);
        g.fillRect(x - radius, y - radius, radius * 2, radius * 2);
    }
}

마우스 드래그 입력이 일어났을때 사용
사용자 이벤트가 발생하였을 경우 필요한 커맨드를 생성하고 MacroCommand 타입의 객체인 history에 추가한다. undo가 필요한 경우엔 버튼이벤트가 발생하였을 경우 history 객체의 undo를
호출하면 된다.

public void mouseDragged(MouseEvent e) {
    Command cmd = new DrawCommand(canvas, e.getPoint());
    history.append(cmd);
    cmd.execute();
}