단순히 타이핑을 통한 계산기 프로그래밍을 단계별로 코드를 수정하면서 제작할 겁니다.
더하기, 빼기, 나누기, 곱하기 연산을 수행할 수 있는 Calculator 클래스를 만들고, 클래스를 이용하여 연산을 진행하고 출력하기
여기서 구현할 때 제가 생각했던 필요한 조건들을 한 번 정리해보겠습니다.
- 값 입력 시
- exit를 입력하면 프로그램 종료
- 어떤 것에도 null이 존재하면 재입력 문구 출력 후 재입력
- 제대로 입력하면 연산 결과 출력
- 연산자
- 연산자에 따라 연산 결과 다르게 만들기
값 입력 시에 대한 조건문을 먼저 만들건데, 값을 한 번 입력하고 끝이 아니라, 특정 문구를 입력하기 전까지는 값을 입력하고 이 결과를 출력하는 것을 반복해 줄 겁니다.
즉, exit 입력시 프로그램이 종료되도록 만드는 것은 exit를 입력하기 전까지는 값과 연산자를 입력하고 이를 반복하는 반복문이 종료되면서 프로그램이 종료된다는 의미입니다.
👉 반복문(while) 안에 값 입력 및 결과 출력 코드를 삽입
//fun main
if(num == "exit") {
println("프로그램 종료")
break
}
그런데 위 코드처럼 작성하니, 무조건 exit를 입력했을 때만 while문에서 탈출하고 다시 반복문으로 돌아오더라구요??? 내부 while문은 탈출했지만 외부 while문에서는 탈출하지 못한 문제였습니다.
그래서 레이블을 이용해 특정 레이블이 지정된 반복문을 종료할 수 있도록 수정했습니다.
// fun main
outer@while(true) {
if(num == "exit") {
println("프로그램 종료")
break@outer
}
}
exit 단어에서 대소문자와 관계없이 만들고 싶었기 때문에 ignoreCase를 이용해서 대소문자와 관계 없이 num이 exit와 동일하다면 이라는 조건으로 변경해 주었습니다.
// fun main
outer@while(true) {
if((num.equals("exit", ignoreCase = true))) {
println("프로그램 종료")
break@outer
}
}


exit, EXIT 뿐만 아니라 Exit, eXit 등 대소문자가 섞여 있어도 프로그램이 종료됩니다.
입력하는 값들 중 어떤 것에도 공백인 null이 존재하면, 즉, 그냥 값 입력 없이 엔터키만 눌렀을 경우에는 재입력하라는 문구가 출력되고 다시 재입력하도록 구현했습니다.
// while
if(num1 == null || num2 == null | operator == null) {
println("잘못 입력하셨습니다. 재입력하세요.")
}
이렇게 하니까 에러가 뜨더라구요.. bool 형식이 아니기 때문에 type 에러 발생.. bool 형태로 변환해서 할까 했지만, 코드가 복잡해질 것 같아 찾아보니 isNullOrBlank()라는 아주 간편한 녀석이 있더라구요 👀 !!
바로 적용시켜주니 원하는대로 프로그램이 작동 되더라구요!
// while
if(num1.isNullOrBlank()) {
println("잘못 입력하셨습니다. 재입력하세요.")
}
근데 여기서 isNullOrBlank 말고도 isNullOrEmpty라는 것도 있길래 무슨 차이점인가 하니!
isNullOrBlank() : 문자열이 null이거나 공백 문자로만 이루어져 있는지 확인.
문자열이 비어있거나 모든 문자가 공백 문자라면 true 반환, 그렇지 않으면 false 반환
isNullOrEmpty() : 문자열이 null이거나 길이가 0인지 확인.
문자열이 비어있거나 null인 경우 true를 반환, 그렇지 않으면 false 반환
근데 어차피 공백인데 isNullOrEmpty를 사용해도 되는거 아닌가? 🤔
NO!❌ 예시를 한 번 들어 볼게요.
num1 = "" // 빈 문자열
num2 = " " // 공백 문자만 포함된 문자열
operator = "" // 빈 문자열
참고 🌟
이때, 사용자가 입력 없이 엔터만 입력했을 경우 null이 아니라 빈 문자열("")이 반환되기 때문에 사용자가 입력한 값이 빈 문자열이어도 null이 아니라는 점!
즉, isNullOrEmpty() 를 사용하게 되면, num2는 공백 문자만 포함되어 있기 때문에 true를 반환하지만 num1, operator의 경우에는 빈 문자열이기 때문에 false를 반환하게 되어 '잘못된 입력' 이라고 생각하지 않고 그대로 출력할 가능성이 있습니다 !
제대로 입력하면 연산이 이루어지고 이 연산이 이루어진 결과를 출력하도록 하겠습니다.
일단 연산이 이루어지기 위해서 when 조건문을 사용해주었습니다. 근데 사실 코틀린을 처음 배우다 보니, when을 사용해야 하는 것은 알겠는데 클래스 내에 바로 선언하니, 에러가 뜨더라구요??
그래서 왜 그런가 하고 찾아보니, 함수 내에 선언을 해주어야 한다는거였죠...
(기초를 놓쳐버린..이런 멍청한 짓을..)
// fun main
// var cal = Calculator()
val result = cal.operate(num1.toDouble(), num2.toDouble(), operator)
println("결과 : ${result}")
// 클래스 Calculator의 fun operate
fun operate(num1:Double, num2:Double, op:String): Double? {
return when (operator) {
"+" -> num1.plus(num2)
"-" -> num1.minus(num2)
"*" -> num1.times(num2)
"/" -> num1.div(num2)
"%" -> num1.rem(num2)
}
else -> null
}
AddOperation(더하기), SubstractOperation(빼기), MultiplyOperation(곱하기), DivideOperation(나누기) 연산 클래스를을 만든 후 클래스간의 관계를 고려하여 Calculator 클래스와 관계 맺기
상속 클래스를 생성하고 이를 이용해서 부모 클래스의 메소드를 재설계하기 위한 오버라이딩을 사용할 겁니다. 상속이므로 open이라는 키워드를 사용해주었습니다.
코드를 만들 때는 조금 복잡하다고 생각했지만, 막상 만들고 나서 코드를 읽어보니 이해가 쉽게 되더라구요!
fun main() {
var result = cal.calculator(num1, num2, operator)
println("결과 : ${result})
}
// 클래스 재설계, operate 함수 calculator로 변경
open class Calculator {
open fun calculator(num1:Double, num2:Double, op:String):Double? {
return when(operator) {
"+" -> num1.plus(num2)
"-" -> num1.minus(num2)
"*" -> num1.times(num2)
"/" -> num1.div(num2)
"%" -> num1.rem(num2)
}
else -> null
}
}
// 더하기
class AddOperation : Calculator() {
override fun calculate(num1:Double, num2:Double, operator:String):Double? {
if(operator == "+") {
return num1.plus(num2)
}
// 부모클래스 구현 사용
return super.calculate(num1, num2, operator)
}
}
// 빼기
class SubstractOperation : Calculator() {
override fun calculate(num1:Double, num2:Double, operator:String):Double? {
if(operator == "+") {
return num1.minus(num2)
}
// 부모클래스 구현 사용
return super.calculate(num1, num2, operator)
}
}
...
이런 식으로 더하기, 빼기, 곱하기, 나누기의 클래스를 부모클래스인 Calculator를 호출해주면 된다.
👉 상속받은 부모클래스를 호출함으로써 부모클래스의 구현을 사용가능
상속을 사용하면 각각의 연산을 Calculator 클래스에 구현했을 때, 코드가 더욱 간단하고 직관적으로 작성할 수 있습니다 ! 객체 5원칙 중 단일책임 원칙을 잘 기억해야 한다.
👉 각 연산이 하나의 클래스로 구현되기 때문에 코드의 구조가 더욱 단순해짐!