카테고리 없음
SOLID - OOP design principle[2] - OCP
Jun.LEE
2024. 3. 8. 12:17
In object-oriented programming, the open–closed principle (OCP) states "software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification"
Open–closed principle - Wikipedia
From Wikipedia, the free encyclopedia Concept in object-oriented programming The open-closed principle was introduced by Bertrand Meyer. In object-oriented programming, the open–closed principle (OCP) states "software entities (classes, modules, function
en.wikipedia.org
위키피디아에서 위와 같이 설명하고 있다. 쉽게 말하자면 확장에는 열려 있어야 하고 수정에는 닫혀 있어야 한다는 말이다.
그럼 예시를 통해서 자세히 알아보자.
class Chef(private val _chefType: Int) {
companion object {
const val KOREA = 0
const val JAPAN = 1
}
fun cook() {
when(_chefType) {
KOREA -> println("한식을 만들어요.")
JAPAN -> println("일식을 만들어요.")
else -> throw Exception("그 셰프님은 없어요.")
}
}
}
fun main() {
val chefList = listOf(
Chef(Chef.KOREA),
Chef(Chef.JAPAN)
)
chefList.forEach { chef ->
chef.cook()
}
}
위 코드가 기존에 사용하던 클래스라고 가정하자.
이때, CHINA와 WESTERN이 추가 된다고 가정하면 다음과 같이 수정해야 한다.
class Chef(private val _chefType: Int) {
companion object {
const val KOREA = 0
const val JAPAN = 1
const val CHINA = 2
const val WESTERN = 3
}
fun cook() {
when(_chefType) {
KOREA -> println("한식을 만들어요.")
JAPAN -> println("일식을 만들어요.")
CHINA -> println("중식을 만들어요.")
WESTERN -> println("양식을 만들어요.")
else -> throw Exception("그 셰프님은 없어요.")
}
}
}
fun main() {
val chefList = listOf(
Chef(Chef.KOREA),
Chef(Chef.JAPAN),
Chef(Chef.CHINA),
Chef(Chef.WESTERN)
)
chefList.forEach { chef ->
chef.cook()
}
}
이는 Extension이 아니라 Modification이 적용된 것이므로 OCP에 위배되는 방식이다.
그러면 위 Chef class를 어떻게 설계하면 수정없이 확장할 수 있을까?
interface Chef {
fun cook()
}
class KoreaChef: Chef {
override fun cook() {
println("한식을 만들어요.")
}
}
class JapanChef: Chef {
override fun cook() {
println("일식을 만들어요.")
}
}
fun main() {
val chefList = listOf(
KoreaChef(),
JapanChef()
)
chefList.forEach { chef ->
chef.cook()
}
}
일단 위 처럼 작성하면 OCP를 고려하지 않은 코드와 비교하였을때 수정 전과 같은 기능을 수행한다.
이때 마찬가지로 CHINA, WESTERN을 추가한다고 하자. 그러면 다음과 같다.
interface Chef {
fun cook()
}
class KoreaChef: Chef {
override fun cook() {
println("한식을 만들어요.")
}
}
class JapanChef: Chef {
override fun cook() {
println("일식을 만들어요.")
}
}
class ChinaChef: Chef {
override fun cook() {
println("중식을 만들어요.")
}
}
class WesternChef: Chef {
override fun cook() {
println("양식을 만들어요.")
}
}
fun main() {
val chefList = listOf(
KoreaChef(),
JapanChef(),
ChinaChef(),
WesternChef()
)
chefList.forEach { chef ->
chef.cook()
}
}
위와 같이 작성하면 Chef 클래스를 수정하지 않고 중식셰프와 양식셰프의 기능을 수행할 수 있게 되었다!