실습 과제 9를 하는데 내가 푼 과제 분석을 하기 위해 글을 작성한다.
State Machine 의 구조(?)
구조는 이렇다.
계산기를 만든다. Operand1은 피연산자, Operator은 연산자, Operand2는 두번째 피연산자이다. 각각을 '상태' 로 변형했다.
처음에는 시작 상태이다. 숫자를 입력받으면 operand1 상태로 넘어가고, 계속해서 숫자를 한 글자씩 입력받는 형태이기 때문에 숫자만 입력하면 계속 Operand1 형태이다. 이런식으로 이어가다가 +, -, \, * 같은 연산자를 입력받으면 Operator 상태로 넘어가며, 여기서 숫자를 입력받으면 Operand2, 연산자를 입력받으면 덮어씌운다. 이렇게 하다가 =을 입력 받으면 피연산자들끼리 계산하는 형식이다.
Main
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
Calculator c = new Calculator();
char ch = sc.next().charAt(0); // 키보드에서 한 글자 입력 받기
while (ch != 'q' && ch != 'Q') {// 종료 문자가 아니면 반복
if(ch == '='){
c.processEqualOperator();
}
else if(ch == '+' || ch == '-' || ch == '/' || ch == '*'){
c.processArithmeticOperator(ch);
}
else{
c.processDigit(ch - '0');
}
ch = sc.next().charAt(0);
}
}
}
처음에 글자를 입력 받은 다음에 종료 버튼인 q가 입력받기 전까지는 계속 반복한다.
sc.next().charAt(0);을 이용해서 한글자씩 입력받는다.
Caculator (context)
public class Calculator {
State state; // 현재 context의 상태
private String op1; //피연산자 1 (숫자를 계속 이어붙일 것이기 때문에 String 형태로 변환한다.)
private String op2; // 피연산자 2 (마찬가지이다.)
private char ope; // 연산자
public Calculator(){
initialize();
state = new StartState(this); //처음에 불려졌을 때는 시작 상태이다.
}
public void initialize(){ //초기화
this.op1 = "";
this.op2 = "";
}
public void caculate(){
if(this.ope=='+'){
int result = ((Integer.parseInt(op1)) + (Integer.parseInt(op2)));
System.out.println("결과 값: " + (Integer.parseInt(op1)) +ope+(Integer.parseInt(op2))+" = "+result);
}
if(this.ope=='-'){
int result = ((Integer.parseInt(op1)) - (Integer.parseInt(op2)));
System.out.println("결과 값: " + (Integer.parseInt(op1)) +ope+(Integer.parseInt(op2))+" = "+result);
}
if(this.ope=='*'){
int result = ((Integer.parseInt(op1)) * (Integer.parseInt(op2)));
System.out.println("결과 값: " + (Integer.parseInt(op1)) +ope+(Integer.parseInt(op2))+" = "+result);
}
if(this.ope=='/'){
int result = ((Integer.parseInt(op1)) / (Integer.parseInt(op2)));
System.out.println("결과 값: " + (Integer.parseInt(op1)) +ope+(Integer.parseInt(op2))+" = "+result);
}
}
public void processDigit(int digit) {
state.processDigit(digit);
}
public void processArithmeticOperator(char ch) {
state.processArithmeticOperator(ch);
}
public void processEqualOperator() {
state.processEqualOperator();
}
public void changeNextState(State state){
this.state = state;
} //setState()
public State getState() {
return state;
}
public String getOp1() {
return op1;
}
public void setOp1(int op1) {
this.op1 += op1;
}
public String getOp2() {
return op2;
}
public void setOp2(int op2) {
this.op2 += op2;
}
public char getOpe() {
return ope;
}
public void setOpe(char ope) {
this.ope = ope;
}
}
한글자씩 숫자(char - 0 으로 변환) 을 입력 받으므로, 일단 String으로 해두고 계속 + 해준다. (int 형이면 더해버리기 때문에)
의문이었던 점은 교수님이 코드에서 각각 State들을 다 멤버변수로 지정하셨는데 이해가 안간다 왜지 ?
우테코 풀면서 객체 참조전달값에 엄청..엄청 고생을 했기 때문에 혹시 그거 때문에 값이 꼬이나? 이생각했다. 그치만 어차피 State에서 상태를 바꾸면 되지 않나(...) 라고 생각했다 😩 내가 뭐라는지 나도 모르겠음ㅋㅋ
Concrete State 들
State를 구현한 Concrete State
public class StartState implements State {
private Calculator calculator;
public StartState(Calculator calculator){
this.calculator = calculator;
}
@Override
public void processDigit(int digit) {
calculator.setOp1(digit);
calculator.changeNextState(new Operand1(calculator));
}
}
public class Operand1 implements State {
private Calculator calculator;
public Operand1(Calculator calculator){
this.calculator = calculator;
}
@Override
public void processDigit(int digit) {
calculator.setOp1(digit);
}
public void processArithmeticOperator(char ch) {
calculator.setOpe(ch);
calculator.changeNextState(new Operator(calculator));
}
}
public class Operator implements State {
private Calculator calculator;
public Operator(Calculator calculator){
this.calculator = calculator;
}
@Override
public void processDigit(int digit) {
calculator.setOp2(digit);
calculator.changeNextState(new Operand2(calculator));
}
public void processArithmeticOperator(char ch) {
calculator.setOpe(ch);
}
}
public class Operand2 implements State {
private Calculator calculator;
public Operand2(Calculator calculator){
this.calculator = calculator;
}
@Override
public void processDigit(int digit) {
calculator.setOp2(digit);
}
public void processEqualOperator() {
calculator.caculate();
calculator.changeNextState(new StartState(calculator));
calculator.initialize();
}
}
리팩토링?
나중에 기회가 되면 하겠지만 new State() 처럼 새로 객체를 생성하는 부분을 싱글톤 패턴으로 바꿔보는 것이다. 시험 전에 언젠간 하겠지?
그리고 우테코 미션도 뭔가 state 패턴으로 바꿔볼 수 있겠다는 생각을 했다. 여러 객체가 링크되어 있어서 고생했던 기억이 나는데...수업에서 배웠던 디자인 패턴을 적용하면 좋을 거 같다.