문제 3 미완성 코드를 추가해 코드를 완성하는 문제입니다. 4개 속성을 선언하고 있지만 초기화를 하지 않았습니다. init 블록에서는 속성 name과 category를 주 생성자(primary constructor)에 전달된 형식 인자로 각각 초기화하면 됩니다. 속성 price와 quantity는 당장 초기화할 수 없으므로 초깃값을 할당해야 합니다.
첫 번째 부 생성자(secondary constructor)는 3개 인자, 두 번째 부 생성자는 4개 인자가 각각 필요합니다. 첫 번째 부 생성자는 3개 인자 중 name과 category의 초기화를 주 생성자로에게 위임하면 됩니다. 두 번째 부 생성자는 4개 인자 중 3개 인자(name, category, price)의 초기화를 첫 번째 부생성자에게 위임하면 됩니다.
class Product(name: String, category: String) { // 주 생성자
private val name: String // 속성 선언
private val category: String
private var price: Double
private var quantity: Int
init {
this.name = name
this.category = category
price = 0.0
quantity = 0
}
constructor(name: String, category: String, price: Double)
: this(name, category) { // 주 생성자 호출
this.price = price
}
constructor(name: String, category: String, price: Double, quantity: Int)
: this(name, category, price) { // 첫 번째 부생성자 호출
this.quantity = quantity
}
}
fun main() {
val mp3 = Product("MP3 player", "Electronics")
val flash = Product("Flash memory", "Electronics", 35.0)
val lego = Product("Lego block", "Toy", 10.0, 54)
}
물론 속성 선언과 함께 초깃값을 할당해도 됩니다.
class Product(name: String, category: String) {
private val name: String = name
private val category: String = category
private var price: Double
private var quantity: Int
init {
price = 0.0
quantity = 0
}
. . . . . .
}
문제 4 과일을 먹었을 때 총 칼로리를 환산하는 함수를 작성하세요. 칼로리 계산을 위해 과일 갯수(단위: 개), 과일 무게(단위: g)를 전달받기 위해 data 클래스 FruitEaten을 추가로 정의했습니다. fruitList 객체는 프로그램 어디서나 참조할 수 있도록 전역 변수로 선언했습니다. 함수 calculateCalories()에서 먹은 과일 갯수와 무게에 따른 칼로리량을 계산합니다.
data class Fruit (val name: String, val sciName:String, val calories:Int)
data class FruitEaten (val name: String, var quantity: Int, var weight: Double)
val fruitList = listOf<Fruit>(
Fruit("Apple", "Malus domestica", 48),
Fruit("Banana", "Musa paradisiaca", 89),
Fruit("Grape", "Vitis vinifera", 69),
Fruit("Orange", "Citrus sinensis",47),
Fruit("Papaya", "Carica papaya", 43),
Fruit("Pineapple", "Ananas comosus", 50),
Fruit("Strawberry", "Fragaria × ananassa", 33),
Fruit("Watermelon", "Citrullus lanatus ", 30))
fun main() {
val fruitEatenList = listOf<FruitEaten>(
FruitEaten("Apple", 2, 340.0),
FruitEaten("Banana", 1, 520.0),
)
val totalCalories = calculateCalories(fruitEatenList)
println("Total calories consumed: ${"%.2f".format(totalCalories)} kcal")
}
fun calculateCalories(felist: List<FruitEaten>): Double {
var total = 0.0
for (item in felist) {
val fruit = fruitList.find { it.name == item.name }
if (fruit == null) return total
total += (item.weight / 100.0) * fruit.calories
}
return total
}
문제 5 교재 p.195-197의 코드는 다형성(polymorphism)을 적용해 다각형의 면적을 계산하는 코드입니다. 이를 sealed class를 사용해 구현하는 문제입니다. 어디가 어떻게 바뀌었는지 비교해 보기 바랍니다. sealed class 를 사용하는 목적은 상속 받는 클래스를 제한하기 위해서이며, 주로 when 문과 함께 사용합니다(아래는 when 문을 사용한 코드로 수정했습니다). sealed class를 사용한 예와 p.197의 메소드 오버로딩(overloading)을 적용한 예를 비교해보기 바랍니다. "사용 목적에 따라 어느 방식이 더 효율적일까" 판단은 전적으로 프로그래머가 결정하는 것입니다.
import kotlin.math.PI
sealed class Shape {
abstract fun getArea(): Double
class Circle(val radius: Double) : Shape() {
override fun getArea(): Double {
return PI * radius * radius
}
}
class Rectangle(val width: Double, val height: Double) : Shape() {
override fun getArea(): Double {
return width * height
}
}
class Triangle(val base: Double, val height: Double) : Shape() {
override fun getArea(): Double {
return (base * height) / 2
}
}
}
fun main() {
val c: Shape = Shape.Circle(5.0)
printArea(c, c.getArea())
val r = Shape.Rectangle(2.0, 5.0)
printArea(r, r.getArea())
val t = Shape.Triangle(3.0, 4.0)
calculateArea(t, t.getArea())
}
fun printArea(c: Shape, area: Double) {
when (c) {
is Shape.Circle -> println("원 면적 = $area")
is Shape.Rectangle -> println("사각형 면적 = $area")
is Shape.Triangle -> println("삼각형 면적 = $area")
}
}
'코틀린' 카테고리의 다른 글
코틀린: fold와 reduce - 누적 합과 누적 곱 (0) | 2025.01.09 |
---|---|
코틀린: 한 걸음 뒤에서 컬렉션의 숲을 바라볼까요? (0) | 2025.01.09 |
코틀린: 4장 테스트에 도전해 보세요 (0) | 2025.01.09 |
코틀린: 멤버 참조 (0) | 2025.01.09 |
코틀린: enum class(updated) (0) | 2025.01.06 |