이번 포스트에서는 SOLID 원칙의 세 번째인 LSP 에 대해서 예시와 함께 다뤄보려고 한다.
LSP (Liscov Substitution Principle)
LSP 는 Liscov Substitution Principle 의 약어로, 리스코프 치환 원칙을 의미한다. LSP 의 개념은 다음과 같다.
Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.
상위 클래스의 객체가 사용하는 메서드는 하위 클래스의 객체가 무엇인지 상관없이, 하위 클래스의 객체도 사용할 수 있어야 한다 .
LSP 를 그대로 해석하면 이해하기 어렵지만, 좀 더 풀어서 설명하면 상위 클래스의 객체를 하위 클래스의 객체로 치환해도 상위 클래스를 사용하는 프로그램은 정상적으로 동작해야 한다는 뜻이다.
사실 설명만으로 바로 이해하기보다, 예시와 함께 알아보는 것이 더 이해하기 쉬울 수 있다. 예시와 함께 알아보자.
LSP 위반 예시
LSP 에 대해 알아보기 위해 다룰 예제로 직사각형과 정사각형을 추상화하여 클래스로 만들고 상속 관계를 설정했다고 가정하자.
수학적으로는 ‘정사각형이면 직사각형이다.’ 라는 명제가 성립하기 때문에 우리는 Fig1 과 같이 설계할 수 있다. Ex1 은 Fig1 의 설계를 Kotlin 을 사용하여 유사하게 구현한 코드이다.
그러나 여기서 직사각형 클래스에 폭 보다 높이를 더 길게 만들어주는 기능이 필요하다고 생각해보자.
fun increaseHeight(rec: Rectangle) {
if(rec.height <= rec.width) {
rec.height = rec.width + 10
}
}
그러나 위 함수를 Rectangle 의 하위 클래스인 Square 클래스의 객체가 사용한다면 높이가 더 길어지지 않는다(폭이 함께 길어짐). 이는 increaseHeight() 함수가 Rectangle 의 확장에 열려 있지 않다는 것을 뜻하기도 한다.
수학적으로 ‘정사각형은 직사각형이다.’ 라는 명제가 성립하지만, 프로그램을 짤 때 ‘Square 객체는 Rectangle 객체이다.’ 로 설계하는 것은 문제가 생길 수 있다는 것이다.
Rectangle 클래스가 width 와 height 프로퍼티를 갖고 있고, Square 객체도 width 와 height 프로퍼티를 갖고 있다. 그리고 각 클래스의 객체는 각각 사각형과 정사각형을 표현할 수 있다.
문제는 Rectangle 객체는 가로 세로 길이를 다르게 만드는 함수로 구현할 수 있으나, Square 객체는 그렇지 않다는 것이다. 왜 이런 구조가 될까? 수학적으로 정사각형은 직사각형보다 제한적이다. 반대로 직사각형은 정사각형보다 자유롭고, 더 많은 정보를 포함할 수 있다. 그러나 프로그래밍에서는 이럴 때 Rectangle 클래스가 Square 클래스를 상속해야 더 적합하다. 상위 클래스의 정보보다 하위 클래스의 정보가 같거나 더 많기 때문이다.
그런데 수학적인 명제와 헷갈릴 수 있다고 생각된다면, 아예 두 클래스의 관계를 끊는 것도 고려해볼 필요가 있다.
LSP 를 지키기 위해 지양해야 할 점 — 상위 클래스 명세를 벗어나는 것, DownCasting
코드적으로는 컴파일에는 문제가 없다. 그러나 위의 예시에서도 볼 수 있듯이 추상화한 타입을 그 하위 타입의 객체로 변환했을 때 예상한대로 동작하지 않는 것을 방지하는 것이 LSP 원칙을 지키는 이유이다.
1. 하위 타입을 정의할 때는 상위 타입의 명세를 지켜야 LSP 를 지킬 수 있다. 따라서 상위 타입에 명세를 명확하게 잘 기록해야 한다.
2. DownCasting 을 사용하면 OCP 를 위반하기도 하지만, LSP 를 위반하기도 한다. 상위 타입의 객체를 하위 타입의 객체로 바꿨을 때 모든 하위 타입에 대해 잘 동작하지 않을 가능성이 크기 때문이다. 또, 상위 타입의 객체가 하위 타입인지 확인하는 코드를 사용하는 것은 상위 클래스가 제대로 추상화되지 않았다는 것을 의미한다.
SOLID 의 다른 원칙 바로가기
Reference
- 최범균, 2014, 객체지향과 디자인 패턴, 인투북스
- [Wikipedia] “SOLID” — https://en.wikipedia.org/wiki/SOLID
- [위키백과] “SOLID (객체 지향 설계)” — https://ko.wikipedia.org/wiki/SOLID_(%EA%B0%9D%EC%B2%B4_%EC%A7%80%ED%96%A5_%EC%84%A4%EA%B3%84)