TIL - 계산기 클래스 만들기

su·2023년 5월 25일
0

TIL

목록 보기
9/93
post-thumbnail

문제1 - 계산기 Class 만들기

1) 문제

문제가 이해가 덜 된듯 하다.
개념이 제대로 잡히지 않아서 그런건지.. 그냥 문제 이해력이 부족한건지..
(둘 다 인듯 ㅠ)
일단 작성은 해봤는데 답안과 다른 부분이 많아서 다시 정리하려고 한다.

2) 시도

더하기, 빼기, 곱하기, 나누기 연산 클래스를 생성하고,
클래스 간 관계를 고려해 Calculator 클래스와 관계를 맺는다.
-> 그렇다면 클래스가 우선 5개 필요하다.

각 연산 클래스 내부에는 operate 라는 이름의 메서드를 정의한다.
반환 타입은 double이며 매개변수는 int 타입으로 두 개이다.
-> public double operate(int a, int b) 처럼 만들면 되는 듯 하다.

처음에는 각 클래스마다 변수를 선언해주어야 한다고 생각해서,

public class AddOperation {
	int fitstNum, secondNum;
    
    // 더하기 연산 - 메소드 정의
    public operate (int firstNum, int secondNum) {
    	this.firstNum = fitstNum;
        this.secondNum = secondNum;
    	return this.firstNum + this.secondNum;
    }
}

이렇게 클래스를 만들어주었는데,
알고보니 이렇게 해 줄 필요가 없었다.
메소드에서 입력받은 매개변수로 계산해서 그 계산결과를 돌려주면 되기 때문에 코드를 다시 작성하면

public class AddOperation { 
    // 더하기 연산 - 메소드 정의
    public operate (int firstNum, int secondNum) {
    	return firstNum + secondNum;
    }
}

이렇게 코드가 나온다!

그리고 Calculate 클래스를 작성해보자.
문제를 올려주실 때, 그림도 함께 올려주셨는데 이해가 잘 안되었다 ..
(그림은 완벽한데 내가 이해를 못함)
그래서 작성해주신 코드와 올려주신 그림을 참조하여 다시 작성해보겠다.

먼저 각 연산 클래스들의 인스턴스를 private로 생성한다.

private AddOperation addOperation = new AddOperation();
private SubstractOperation substractOperation = new SubstractOperation();
private MultiplyOperation multiplyOperation = new MultiplyOperation();
private DivideOperation divideOperation = new DivideOperation();

그리고 생성한 인스턴스를 활용해 생성자를 만들어준다.

public Calculator (AddOperation addOperation, SubstractOperation, substractOperation,
				   MultiplyOperation multiplyOperation, DivideOperation divideOperation) {
	this.addOpertaion = addOperation;
    this.substractOperation = substractOpertaion;
    this.multiplyOperation = multiplyOperation;
    this.divideOperation = divideOperation;
}

위에서 인스턴스를 private으로 선언했으므로, 그 인스턴스에 접근하기 위해 생성자에 입력받은 매개변수 값을 넣어준다.

그 후 calculate 메소드를 만들어준다.

public double calculate(String s, int firstNum, int secondNum) {
	switch(s) {
    	case "+" :
        	return addOperation.operate(firstNum, secondNum);
        case "-" :
        	return substractOperation.operate(firstNum, secondNum);
        case "*":
        	return multiplyOperation.operate(firstNum, secondNum);
        case "/" :
        	return divideOperation.operate(firstNum, secondNum);
        default :
        	return 0;
    } // switch문 종료
} // calculate 메소드

if~else 문으로도 작성해봐야지.

public double calculate(String s, int firstNum, int secondNum) {
	if (Objects.equals(s, "+")) {
        return addOperation.operate(firstNum, secondNum);
    } else if (Objects.equals(s, "-")) {
        return substractOperation.operate(firstNum, secondNum);
    } else if (Objects.equals(s, "*")) {
        return multiplyOperation.operate(firstNum, secondNum);
    } else if (Objects.equals(s, "/")) {
        return divideOperation.operate(firstNum, secondNum);
    } else {
        return 0;
    } // if~else문 종료
} // calculate 메소드

했는데,, 작성하신 코드가 나와 다르다 ..!!

public double calcuate(String operator, int firstNumber, int secondNumber) {
	double answer = 0;
    if (operator.equals("+")) {
    	answer = addOperation.operate(firstNumber, secondNumber);
    } else if (operator.equals("-")) {
    	answer = substractOperation.operate(firstNumber, secondNumber);
    } else if (operator.equals("*")) {
    	answer = multiplyOperation.operate(firstNumber, secondNumber);
    } else if (operator.equals("/")) {
    	answer = divideOpertaion.operate(firstNumber, secondNumber);
    }
    return answer;
}

각 조건마다 그 조건에 해당하면 생성한 answer 변수에 값을 대입하고
마지막에 return문을 한 번만 작성해 주셨다!

3) 해결

public class AddOperation {
    // 더하기 연산 - 메소드 정의
    public operate (int firstNum, int secondNum) {
    	return firstNum + secondNum;
    }
}
public class SubstractOperation {
    // 빼기 연산 - 메소드 정의
    public operate (int firstNum, int secondNum) {
    	return firstNum - secondNum;
    }
}
public class MultiplyOperation {
    // 곱하기 연산 - 메소드 정의
    public operate (int firstNum, int secondNum) {
    	return firstNum * secondNum;
    }
}
public class DivideOperation {
    // 나누기 연산 - 메소드 정의
    public operate (int firstNum, int secondNum) {
    	return firstNum / secondNum;
    }
}
public class Calculator {
	public static void main(String[]args) {
    	// 우선 각 연산 클래스들의 인스턴스를 생성한다.
        private AddOperation addoperation = new AddOperation();
        private SubstractOperation substractOperation = new SubstractOperation();
        private MultiplyOperation multiplyOperation = new MultiplyOperation();
        private DivideOperation divideOperation = new DivideOperation();
        
        // Calculator 생성자
        public Calculator (AddOperation addOperation, SubstractOperation substractOperation,
                          MultiplyOperation multiplyOpertaion DivideOperation divideOperation) {
        	this.addOperation = addOperation;
            this.substractOperation = substractOpertaion;
            this.multiplyOperation = multiplyOperation;
            this.divideOperation = divideOperation;
        } // 생성자
    	
        // calculate 메소드
        public calculate (String s, int firstNum, int secondNum) {
        	switch (s)  {
            	case "+":
                	return addOpertaion.operate(firstNum, secondNum);
             	case "-":
                	return substractOpertaion.operate(firstNum, secondNum);
                case "*":
                	return multiplyOperation.operate(firstNum, secondNum);
                case "/":
                	return divideOperation.operate(firstNum, secondNum);
                default:
                	return 0;
            
            } //switch문 종료
        } // 메소드
    }
}
public class Main{
	public static void main (String[]args){
    	Calculator calculator = new Calculator (new AddOpertaion(), new SubstractOperation(), 
                                                new MultiplyOperation(), new DivideOperation());
        System.out.println(calculator.calculate("+", 10, 20));
        System.out.println(calculator.calculate("-", 10, 20));
        System.out.println(calculator.calculate("*", 10, 20));
        System.out.println(calculator.calculate("/", 10, 20));
    }
}

문제에서 언급한 Calculator 클래스와 , 각 연산 클래스 4개, Main 클래스까지
총 6개의 클래스를 만들 수 있다!
혼자서 쭉 코드를 써보니 더 이해가 잘 되는 것 같다.

4) 배운 점

지금 작성한 코드는 step3 인데,
step2에서 작성한 코드에 비해 각 연산자별로 클래스가 4개가 늘어났다.
각 클래스마다 연산을 하나씩 담당하게 되었다!
다른 클래스들을 필요한 클래스에서 다시 인스턴스 형태로 불러오고,
그 인스턴스로 생성자를 만들어서 사용한다는 점을 알게 되었다.
그리고 switch 문을 쓸 때, 각 case 마다 break를 해주지 않으면 계속해서 밑으로 흐르기 때문에 break를 꼭 넣어주어야 한다고 배웠는데,
case마다 return을 해주고 break를 넣으면 오류가 났다 ..!
return을 해주기 때문에 거기서 코드가 종료되므로 break가 실행되지 않아 오류가 난 것이다.
return문이 있으면 break는 적지 않아야 하는 것 같다!

문제2 - 계산기 Class 만들기 (2)

1) 문제

더 발전된 계산기를 만들어야 한다 !
이번엔 각 연산클래스들을 AbstractOperation이라는 추상 클래스를 이용해 추상화하여야 한다.
주의할 점은 Calculator의 calculate 메서드이 매개변수가 변경되었다는 점이다.

2) 시도

먼저 새롭게 생긴 추상 클래스를 정의해보자 !
추상 클래스 안에는 double 타입의 operate 메서드가 정의되어야 한다.

public abstract class AbstractOperation {
	public abstract double operate (int firstNum, int secondNum);
}

그리고 각 연산자 클래스는 추상 클래스를 상속받아 operate를 재정의한다.
즉 operate 메소드를 오버라이딩 한다.

public class AddOperation extends AbstractOperation {
	@Override
    public double operate (int firstNum, int secondNum) {
    	return firstNum + secondNum;
    }
}

이제 Calculator 클래스를 수정한다.
abstractOperation 타입의 필드를 선언하고,
calculate를 수정한다

사실 여기서 막혔었다.
작성된 코드를 하나씩 다시 살펴보려고 한다!
우선, 문제에서 요구한 대로 AbstractOperation 형태의 필드를 정의한다.

private AbstractOperation operation;

앞서 작성했던 4개의 필드가 사라졌으니 생성자도 수정이 필요하다.

public Calculator (AbstractOperation operation) {
	this.operation = operation;
}

추가할 메소드가 생겼다 !
private으로 선언한 operation의 값을 수정할 때 필요한 setting 메소드가 필요하다.
추상 클래스인 AbstractOperation 클래스를
AddOperation, SubstractOpertaion, MultiplyOperation, DivideOperation가 각각 상속받으므로
각 클래스로 생성된 인스턴스에 접근 가능하게 하려면 (각 클래스의 메소드를 사용하려면)
setting 메소드가 필요하다.

public void setOperation(AbstractOperation operation) {
	this.operation = operation;
}

여기서 반환 타입이 void인 이유에 대해서 찾아보았다.
처음에는 반환할 타입이 정해져 있지 않아서 그런가 ? 했었는데
출처: 클라우드스터딩 - void
void를 찾아보니 void 타입의 메소드는 값을 반환하지 않는다 라고 한다.
만약 void 타입 메서드에 return이 사용되었다면 값을 반환하는 것이 아닌 메소드 종료이다.

작성한 setOperation 메소드는 반환할 값이 없기 때문에 void 타입으로 선언해 준 듯 하다.

그리고 마지막으로 calculate 메소드를 수정한다.

public double calculate (int firstNum, int secondNum) {
	return operation.operate(firstNum, secondNum);
}

이렇게 Calculator 클래스를 다시 작성할 수 있다.

그리고 Main 클래스를 수정한다.

public clss Main {
	public static void main(String [] args) {
    	// Calculator 인스턴스 생성하기 - 더하기 사용
        Calculator calculator = new Calculator(new AddOperation());
        // 더하기 메소드 호출하기
        System.out.println(calculator.calculate(10, 20));
        
        // 인스턴스 수정 - 곱하기 호출
        calculator.setOperation(new MultiplyOperation());
        // 곱하기 메소드 호출하기
        System.out.println(calculator.calculate(10, 20));
    }
}

원하는 대로 잘 출력되는 것을 확인할 수 있었다.

3) 해결

Calculator.java

public class Calculator {
	// 추상 클래스 인스턴스 생성
	private AbstractOperation operation;
    // Calculator 생성자
    public Calculator (AbstractOperation operation) {
    	this.operation = operation;
    }
    // private으로 선언한 operation을 set 할 수 있는 메소드 정의
    public void setOperation(AbstractOperation operation) {
		this.operation = opertaion;
    }
	// calculate 메소드
	public double calculate (int firstNum, int secondNum) {
    	return operation.operate(firstNum, secondNum);
    }
}

그리고 main 메소드를 조금 수정해보려고 한다 !
Main.java

public class Main{
	public static void main (String [] args) {
    	Calculator calculator;
        int firstNum, secondNum;
        Scanner sc = new Scanner(System.in);

        System.out.print("연산자를 입력하세요( + | - | * | / ): ");
        String op = sc.nextLine();

        switch (op) {
            case "+" :
            	System.out.print("피연산자를 띄어쓰기로 입력하세요: ");
        		firstNum = sc.nextInt();
        		secondNum = sc.nextInt();
                calculator = new Calculator(new AddOperation());
                System.out.println(firstNum + " + " + secondNum + " = " + calculator.calculate(firstNum, secondNum));
                break;
            case "-" :
            	System.out.print("피연산자를 띄어쓰기로 입력하세요: ");
        		firstNum = sc.nextInt();
        		secondNum = sc.nextInt();
                calculator = new Calculator(new SubstractOperation());
                System.out.println(firstNum + " - " + secondNum + " = " + calculator.calculate(firstNum, secondNum));
                break;
            case "*" :
            	System.out.print("피연산자를 띄어쓰기로 입력하세요: ");
        		firstNum = sc.nextInt();
        		secondNum = sc.nextInt();
                calculator = new Calculator(new MultiplyOperation());
                System.out.println(firstNum + " * " + secondNum + " = " + calculator.calculate(firstNum, secondNum));
                break;
            case "/" :
            	System.out.print("피연산자를 띄어쓰기로 입력하세요: ");
        		firstNum = sc.nextInt();
        		secondNum = sc.nextInt();
                calculator = new Calculator(new DivideOperation());
                System.out.println(firstNum + " / " + secondNum + " = " + calculator.calculate(firstNum, secondNum));
                break;
            default:
                System.out.println("잘못 입력하셨습니다.");
        } //switch문 종료
    }
}

실행은 잘 되는데, 겹치는 코드가 너무 눈에 잘 보인다 ..
코드를 다시 작성해봐야겠다 ..!

코드를 수정하여 깃 허브에 올려두었다
gitHub: gitHub - Java 3주차 숙제 step4

4) 배운 점

문제를 정확하게 이해하는 능력도 필요한 것 같다.
문제에서 요구하는 바를 정확하게 이해하고 코드로 옮기려는 노력이 필요할 듯 하다.
추상 클래스에서 작성한 추상 메소드는 반드시 오버라이딩 (재정의) 해주어야 하며,
오버라이딩을 할 경우, 메소드의 이름, 메소드에 들어갈 매개변수의 종류와 개수, 메소드의 타입 모두 일치해야함을 기억해야 한다 !

그리고 gitHub에 push할 때 조심해야 한다.
branch를 바꾸고 파일을 수정했어야 하는데,
깜빡하고 그냥 main 브랜치에서 작업하고 push 하려고 하다보니
이전에 commit 사항이 반영되지 않았다 ..? 라는 문구가 떠서 force push 라는 것을 눌렀더니
열심히 작성했던 코드가 이전 코드들로 돌아왔다 ..^^
다시 새로운 마음으로 작성하긴 했지만, git에 파일을 push 하려면 주의해야겠다 !

profile
(❁´◡`❁)

0개의 댓글