리스코프 치환 원칙(LSP)이란?
리스코프 치환 원칙은 객체 지향 설계의 SOLID 원칙 중 세 번째 원칙이다. 서브타입은 언제나 기반 타입으로 교체할 수 있어야 한다는 원칙이다. 이는 프로그램의 정확성을 유지하기 위해 매우 중요하다.
잘못된 예제부터 봅시다.
class Bird {
func fly() {
print("Flying")
}
}
class Ostrich: Bird {
override func fly() {
fatalError("Ostriches can't fly!")
}
}
이 예제에서는 Ostrich 클래스가 Bird 클래스를 상속받고 있지만, fly 메서드를 제대로 구현하지 못한다. 이는 리스코프 치환 원칙을 위반하는 예이다.
다음은 올바른 예제이다.
class Bird {
func fly() {
print("Flying")
}
}
class Ostrich {
func run() {
print("Running")
}
}
class Aviary {
func letBirdFly(bird: Bird) {
bird.fly()
}
func letOstrichRun(ostrich: Ostrich) {
ostrich.run()
}
}
// 사용 예시
let bird = Bird()
let ostrich = Ostrich()
let aviary = Aviary()
aviary.letBirdFly(bird: bird) // 출력: Flying
aviary.letOstrichRun(ostrich: ostrich) // 출력: Running
이 예제에서는 Ostrich 클래스가 Bird 클래스를 상속받지 않고 독립적으로 동작한다. 이를 통해 리스코프 치환 원칙을 준수할 수 있다.
LSP를 준수함으로써 얻을 수 있는 장점
- 예측 가능성: 서브타입이 기반 타입의 행동을 따르기 때문에 예측 가능성이 높아집니다.
- 재사용성: 서브타입이 기반 타입을 교체 가능하므로 코드 재사용이 쉬워집니다.
- 유지보수성: 변경이 최소화되어 코드 유지보수가 용이합니다.