2018-4-23 Bowling에서 인터페이스를 적용하기

인터페이스를 통해서 적용하기

  • 처음에는 볼링에서 Shoot에 대한 설계를 못해서 많이 엎고 시작을 했는데, 지난주에는 많이 완성을 했었다. 그러다가 오늘 다시 State에 대한 부분을 완전히 재설계를 들어갔다.
public interface State {
    String displayText();

    State bowl(int first);

    boolean isFinish();
}
  • 우선 지난주까지 Status라는 상태값을 이용해서, 2개의 핀값을 받고 다른상태값들이 Status를 상속을 받아서 객체를 리턴해주는 형식을 좀 더 추상화를 해서 State라는 인터페이스로 바꾸고, 여기서 상태값, 샷에 대한 정보, 그리고 프레임이 끝났는지 유무를 판단을 해주게된다. 인터페이스에 대한 설계를 이번에 많이 고민을 하고 적용을 한거같다.
public class Frame {
    public State state = new Ready();

    public State bowl(int pin) {
        state = state.bowl(pin);
        return state;
    }
}
  • 처음에 프레임을 설계를 했을때는 프레임이 끝났는지, 그리고 샷, 2개의 핀을 받고 여기서 상태를 체크해주는 많은 메소드들이 있었는데, 프레임이 굉장히 심플해졌다.
  • 아무것도 없는 상태를 Ready라는 상태로 정의를 했다. 여기에는 빈값들이 존재를 하게 된다.
public class Ready implements State {
    @Override
    public String displayText() {
        return null;
    }

    public State bowl(int first) {
        if (first == 10)
            return new Strike();
        return new FirstBowl(first);
    }

    @Override
    public boolean isFinish() {
        return false;
    }
}
  • Ready 클래스는 State에 있는 추상메소드들을 구현을 하게 된다.
  • displayText메소드에는 빈값이 들어가 있기대문에, 아무것도 표시되는 것이 없고
  • bowl을 통해서 샷을 받고 그리고 여기서 첫번째샷의 값이 10이면 스트라이크를 아니면 FirstBowl의 상태를 리턴을 해주게 된다.
  • 물론 isFinish의 메소드는 당연히 False가 된다.
package status;

public class Strike implements State {
    @Override
    public String displayText() {
        return "X";
    }

    @Override
    public State bowl(int first) {
        throw new IllegalArgumentException();
    }

    @Override
    public boolean isFinish() {
        return true;
    }
}

  • 스트라이크 클래스는 위와 같이 State에서 추상메소드들을 구체화를 하게 되고, 여기서 주목할점은 bowl에 대한 부분이다. 더 이상 받을 수 있는 bowl이 없기때문에 예외처리를 하게되고, isFinish는 당연히 True를 리턴을 하게 된다.
public class FirstBowl implements State {
    private int first;

    public FirstBowl(int first) {
        this.first = first;
    }

    @Override
    public String displayText() {
        return first;
    }

    @Override
    public State bowl(int second) {
        if (this.first + second == 10)
            return new Spare(first);
        return new Miss(first, second);
    }

    @Override
    public boolean isFinish() {
        return false;
    }
}
  • FirstBowl에 대한 부분은 firstShoot에 대한 정보를 입력을 받고, 처음에 입력값을 상태값을 콘솔에다가 출력을 해준다.
  • Bowl에서 secondShoot을 입력을 받는데, 여기서 스페어냐 미스냐 둘 중 하나의 상태값을 리턴을 하게 된다. 물론 isFinish의 값은 당연히 False이다.
public class Miss implements State {
    private int first;
    private int second;

    public Miss(int first, int second) {
        this.first = first;
        this.second = second;
    }

    @Override
    public String displayText() {
        return "|" + String.valueOf(second) + " |";
    }

    @Override
    public State bowl(int first) {
        throw new IllegalArgumentException();
    }

    @Override
    public boolean isFinish() {
        return true;
    }
}
public class Spare implements State {
    private int first;

    public Spare(int first) {
        this.first = first;
    }

    @Override
    public String displayText() {
        return "/";
    }

    @Override
    public State bowl(int first) {
        throw new IllegalArgumentException();
    }

    @Override
    public boolean isFinish() {
        return true;
    }
}
  • 위의 Spare, Miss의 경우에는 프레임이 종료가 된다는 점에서는 동일하다. 그리고 secondShoot의 경우에는 예외처리를 통해서 방지를 했다.

오늘의느낀점

  • State에 대한 부분을 인터페이스화를 시키고 이를 기반으로 상태값들을 가지는 클래스들을 설계를 할때 많은 뿌듯함이 있었다. 지난주에는 상속에 대한 부분을 적용을 하고 생각을 하면서 추상화를 어떻게 시킬 수 있는가에 대한 생각이 많았다.
  • 아직까지 추상클래스, 인터페이스에 대한 차이를 설명을 하라고 하면 잘 모르고 또 구현을 할때 어떤 차이점이 있는지에 대한 부분은 잘 모르겠다. 이전에 개념을 공부를 할때, 어떤거다라는 정도만 공부를 했기때문이다. 이제는 볼링을 구현을 하면서 객체를 추상화를 하는 부분에 대해서 직접 적용을 하고 파고 들어봐야겠다.
  • 로또에서도 많이 배웠지만, 볼링에서는 객체를 추상화를 하는 인터페이스, 상속을 좀 더 공부를 하고 내가 잘 적용하지 못했던 예외처리에 대한 부분을 잘 적용을 해야겠다.
Written on April 23, 2018