포토샵의 여러개의 툴을 생각해보자. 연필을 선택하면 연필로 그려져야되고, 지우개를 선택하면 지워져야 된다. 이처럼 어떤 툴을 선택했느냐에 따라서 같은 사용자 행동이 다른 결과를 만들어내야될 때가 있다.

  public void mouseUp() {
    if(type == "erase") {
      ...
    } else if (type == "pencil") {
      ...
    }
  }

이렇게 타입별로 if/else 형태로 나눠서 구현을 할 수도 있다. 그런데 새로운 툴을 추가하려면 다시 else if를 추가해야 되고, mouseUp과 같은 매소드가 여러개 있다면 일일이 다 고쳐야 될거다.

앞에서 배웠던 polymorphism을 이용해서, 확장성있는 형태로 바꿔보자.

우선 툴타입을 정의해두자.

// ToolType.jsva
public enum ToolType {
    SELECTION,
    BRUSH,
    ERAGER,
}

Tool absctract class를 만들자. interface로도 구현할 수 있다.

public class abstract Tool {
  public void abstract mouseUp()
  public void abstract mouseDown()
}
public interface Tool {
  void mouseUp()
  void mouseDown()
}

이제 새로운 도구가 추가될때는, 이 Tool interface를 구현한 class를 정의해주는 형태로 추가해 나갈 수 있다.

public class BrushTool implements Tool {
    @Override
    public void mouseUp() {
        System.out.println("Brush icon");
    }

    @Override
    public void mouseDown() {
        System.out.println("Draw a line");
    }
}
public class EraserTool implements Tool {
    @Override
    public void mouseUp() {
        System.out.println("Eraser icon");
    }

    @Override
    public void mouseDown() {
        System.out.println("Erase");
    }
}

BrushToolEraserTool이 있는 상태에서 새로운 도구, SelectionTool을 추가하려면 어떻게 해야 될까? 앞서 말했듯이 새롭게 class를 정의하고, Tool interface의 mouseUpmouseDown을 구현하면 된다.

public class SelectionTool implements Tool {
    @Override
    public void mouseUp() {
        System.out.println("Selection icon");
    }

    @Override
    public void mouseDown() {
        System.out.println("Draw dashed rectangle");
    }
}

자 이제 이 도구를 사용하는 Canvas 클래스를 만들어 보자.

public class Canvas {
    private Tool currentTool;

    public void mouseDown() {
        // delegating
        currentTool.mouseDown();
    }

    public void mouseUp() {
        currentTool.mouseUp();
    }

    public Tool getCurrentTool() {
        return currentTool;
    }

    public void setCurrentTool(Tool currentTool) {
        this.currentTool = currentTool;
    }
}

Cavas 클래스는, 현재 선택된 도구의 statecurrentTool attribute로 가지고 있게 된다. state패턴은 이 state가 변경될 때 마다 다른 행동을 만들수 있게 해준다.

//Main.java
  public static void main(String[] args) {
    Canvas canvas = new Canvas();
    canvas.setCurrentTool(new EraserTool());
    canvas.mouseDown();
    canvas.mouseUp();
  }

EraserTool을 선택하고 나면, 이제부터 mouseDown, mouseUpEraserTool 클래스에 정의된 함수가 실행되게 된다.

BrushTool로 변경하고 싶으면 아래와 같이 currentTool state를 변경해주면 된다.

canvas.setCurrentTool(new BrushTool())