정의
- 부모 클래스에서 구현해야할 객체의 단계를 전체적으로 정의한다음, 자식 클래스마다 달라지는 단계에 대해서만 부모 클래스단에서 추상 메서드로 정의하여 자식클래스가 해당 메서드를 오버라이드할 수 있게 하는 패턴
목적
- 비슷한 개념을 가진 객체들의 중복되는 코드는 부모클래스에서 정의하기에 코드 길이가 줄어들며, 관리하기가 용이하다.
- 해당 패턴을 사용하지 않을 경우
class Coffee {
fun make(): List<String> {
val result = mutableListOf<String>()
result.add("물을 끓입니다.")
result.add("커피 원두를 내립니다.")
result.add("컵에 따릅니다.")
result.add("설탕과 우유를 넣습니다.")
return result
}
}
class Tea {
fun make(): List<String> {
val result = mutableListOf<String>()
result.add("물을 끓입니다.")
result.add("찻잎을 우립니다.")
result.add("컵에 따릅니다.")
result.add("레몬을 넣습니다.")
return result
}
}
- 두 클래스 모두 서로 비슷한 개념을 가진 객체들이며, 물을 끓입니다와 컵에 따릅니다 라는 과정이 겹치는 문구가 나타난다.
코드
abstract class Beverage {
fun make(): List<String> {
val result = mutableListOf<String>()
result.add(boilWater())
result.add(brew())
result.add(pourInCup())
result.add(addCondiments())
return result
}
private fun boilWater(): String {
return "물을 끓입니다."
}
protected abstract fun brew(): String
private fun pourInCup(): String {
return "컵에 따릅니다."
}
protected abstract fun addCondiments(): String
}
- Beverage 라는 부모클래스를 별도로 만들어서 겹치는 과정은 부모클래스단에서 정의하며,
- protected abstract fun brew(): String
protected abstract fun addCondiments(): String
- 자식 클래스마다 달라질만한 부분들은 별도로 abstract로 선언하여 추상 메서드로서 선언한다.
class Coffee : Beverage() {
override fun brew(): String {
return "커피 원두를 내립니다."
}
override fun addCondiments(): String {
return "설탕과 우유를 넣습니다."
}
}
class Tea : Beverage() {
override fun brew(): String {
return "찻잎을 우립니다."
}
override fun addCondiments(): String {
return "레몬을 넣습니다."
}
}
- 추상 메서드를 자식클래스에서 위와같이 구현한다.
- 이러면 자식클래스들이 지켜야할 부모클래스의 전체적인 단계를 따르면서도 공통 부분들은 굳이 따로 자식단에서 구현하지 않아도 되며, brew()와 addCondiments() 함수 또한 부모가 정한 함수 이름·매개변수·반환 타입을 지키기에 이부분에 있어서도 나름의 통일성을 가진다.