확장에는 열려있으나 변경에는 닫혀있어야 한다는 원칙
어떤 기능을 추가할 때, 기존의 코드는 만지지 않고 새로 동작하는 기능에 대해서만 코드가 작성되어야 한다. 이런 원칙을 지키기 위해서는 다양한 방법들이 있다.
프로토콜을 활용할 수 있다. 만약 동물의 소리를 내는 동물원이라는 변수가 있는데 여기에 새로운 동물이 추가된다고 생각하면 어떻게 구현했느냐에 따라 OCP를 지키느냐 안지키느냐로 나뉠 수 있다.
이전의 SRP 예제에서도 프로토콜을 이용해서 OCP원칙을 잘 지키고 있다. 만약 새롭게 DB, API Call, Decoding의 로직을 수행하고 싶으면 단지 각각의 프로토콜을 구현하고 있는 객체를 외부에서 주입하면 되기 때문에 새로운 기능에도 변화없이 대응 가능하게 된다.
안좋은 예
class Dog {
func makeSound(){
print("멍멍")
}
}
class Cat {
func makeSound() {
print("야옹")
}
}
class Zoo{
var dogs: [Dog] = [Dog(), Dog(), Dog()]
var cats: [Cat] = [Cat(), Cat(), Cat()]
func makeAllSounds(){
dogs.forEach{
$0.makeSound()
}
cats.forEach{
$0.makeSound()
}
}
}
여기서 만약 새로운 동물이 추가되면 어떻게 될까?
class로 정의한 새로운 동물을 정의하고 Zoo에 또 기존의 코드를 만져서 수정을 진행하게 될 것이다. 이렇게 되면 OCP의 원칙을 어기고 설계되는 것이다.
좋은 예
protocol Animal{
func makeSound()
}
class Dog: Animal {
func makeSound(){
print("멍멍")
}
}
class Cat: Animal {
func makeSound() {
print("야옹")
}
}
class Zoo{
var animals: [Animal] = []
func makeAllSounds(){
animals.forEach{
$0.makeSound()
}
}
}