공부/이펙티브코틀린
아이템39 - 태그 클래스보다는 클래스 계층을 사용하라
띵커베르
2024. 8. 1. 22:49
728x90
태그 클래스(tagged class): 상수 모드를 태그라고 부르고, 태그를 포함한 클래스
-> 객체 타입을 나타내기 위해 필드를 사용하고, 해당 필드에 따라 동작이 달라지는 클래스를 의미.
- 태그 클래스의 문제점:
- 복잡성 증가: 하나의 클래스에 여러 유형의 객체를 처리하기 위한 코드가 포함되어 복잡성이 증가합니다.
- 유지보수 어려움: 새로운 유형이 추가될 때마다 기존 코드를 수정해야 하므로 유지보수가 어렵습니다.
- 가독성 저하: 태그를 기반으로 분기하는 코드가 많아지면 코드의 가독성이 떨어집니다.
- 클래스 계층의 장점:
- 명확한 구분: 각 클래스가 자신의 책임을 가지므로 코드가 명확해집니다.
- 확장성: 새로운 유형을 쉽게 추가할 수 있습니다.
- 유지보수 용이: 각 클래스가 독립적이기 때문에 수정이 용이합니다.
태그 클래스 사용 예시:
enum class ShapeType {
CIRCLE, RECTANGLE, TRIANGLE
}
class Shape(val type: ShapeType, val radius: Double = 0.0, val width: Double = 0.0, val height: Double = 0.0)
fun area(shape: Shape): Double {
return when (shape.type) {
ShapeType.CIRCLE -> Math.PI * shape.radius * shape.radius
ShapeType.RECTANGLE -> shape.width * shape.height
ShapeType.TRIANGLE -> 0.5 * shape.width * shape.height
}
}
fun main() {
val circle = Shape(ShapeType.CIRCLE, radius = 2.0)
val rectangle = Shape(ShapeType.RECTANGLE, width = 2.0, height = 3.0)
val triangle = Shape(ShapeType.TRIANGLE, width = 2.0, height = 4.0)
println("Circle area: ${area(circle)}")
println("Rectangle area: ${area(rectangle)}")
println("Triangle area: ${area(triangle)}")
}
클래스 계층 사용 예시:
abstract class Shape {
abstract fun area(): Double
}
class Circle(val radius: Double) : Shape() {
override fun area() = Math.PI * radius * radius
}
class Rectangle(val width: Double, val height: Double) : Shape() {
override fun area() = width * height
}
class Triangle(val base: Double, val height: Double) : Shape() {
override fun area() = 0.5 * base * height
}
fun main() {
val shapes: List<Shape> = listOf(
Circle(2.0),
Rectangle(2.0, 3.0),
Triangle(2.0, 4.0)
)
for (shape in shapes) {
println("Area: ${shape.area()}")
}
}
sealed 클래스 사용 예시:
sealed class Shape {
abstract fun area(): Double
}
class Circle(val radius: Double) : Shape() {
override fun area() = Math.PI * radius * radius
}
class Rectangle(val width: Double, val height: Double) : Shape() {
override fun area() = width * height
}
class Triangle(val base: Double, val height: Double) : Shape() {
override fun area() = 0.5 * base * height
}
fun describeShape(shape: Shape): String {
return when (shape) {
is Circle -> "This is a circle with radius ${shape.radius}"
is Rectangle -> "This is a rectangle with width ${shape.width} and height ${shape.height}"
is Triangle -> "This is a triangle with base ${shape.base} and height ${shape.height}"
}
}
fun main() {
val shapes: List<Shape> = listOf(
Circle(2.0),
Rectangle(2.0, 3.0),
Triangle(2.0, 4.0)
)
for (shape in shapes) {
println(describeShape(shape))
println("Area: ${shape.area()}")
}
}
좀 다른 얘기긴 해도..
개인적으로 enum 코드를 주로사용하지만 when 에서 강제하기 위해서는 sealed 한정자를 써봐야겠다.
728x90