리스코프 치환 원칙 (LSP: Liskov Substitution Principle)
S가 T의 하위 유형이면 프로그램에서 자료형 T의 객체는 해당 프로그램의 원하는 속성을 변경하지 않고 자료형 S의 객체로 교체(치환)할 수 있어야 한다.
바바라 리스코프(Babara Liskov)
로버트 C마틴은 이것을 다음과 같이 요약했습니다.
자식 클래스는 부모 클래스를 대체할 수 있어야 한다.
이 원칙의 핵심은 부모 클래스를 사용하는 위치에 자식 클래스를 대신 사용했을 때 코드가 원래 의도대로 작동해야 한다는 것을 의미합니다.
LSP 위반 사례
일반적으로 많이 드는 예시가 바로 직사각형을 상속한 정사각형 클래스의 예시입니다.
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def get_area(self):
return self.width * self.height
def set_width(self, value):
self.width = value
def set_height(self, value):
self.height = value
class Square(Rectangle):
def __init__(self, side):
self.width = side
self.height = side
def set_width(self, value):
self.width = value
self.height = value
def set_height(self, value):
self.width = value
self.height = value
정사각형은 직사각형의 한 종류이기 때문에 정사각형은 직사각형을 상속받을 수 있습니다.
728x90
그러나 Rectangle 객체를 Square 객체로 바꾸면 어떤 일이 발생하는지 살펴보겠습니다.
r = Rectangle(4,5)
r.set_width(5)
r.set_height(6)
print(r.get_area())
r1 = Square(4)
r1.set_width(5)
r1.set_height(6)
print(r1.get_area())
위 코드에서 Rectangle 객체를 Squear로 대체한 것을 볼 수 있고 이 코드의 결과는 아래와 같습니다.
30
36
정사각형의 특징때문에 길이와 너비를 동일한 값으로 설정하려고 Rectangle클래스의 set_width, set_height를 변경했기 때문에 결과가 다르게 나왔습니다. 이는 LSP를 위반합니다.
정사각형은 직사각형일 수 있지만 Squer 객체는 Rectangle 객체가 아닙니다. 이는 Square 객체의 동작이 Rectangle 객체의 동작과 일치하지 않기 때문입니다.
결론
LSP는 자식클래스가 오류를 일으키지 않고 부모 클래스를 대신할 수 있도록 하는 것을 목표로 합니다.
LSP를 지키면 OCP(Open Closed Principle)를 확장하고 응용 프로그램을 중단하지 않고 상위 클래스의 객체를 하위 클래스의 객체로 바꿀 수 있습니다. 이를 위해서는 모든 하위클래스가 상위 클래스와 동일한 방식으로 동작해야 합니다.