리스코프 치환 원칙(LSP)
"상위 타입의 객체를 하위 타입의 객체로 치환해도 상위 타입을 사용하는 프로그램은 정상적으로 동작해야 한다."
즉, 특정 메소드가 상위 타입을 인자로 사용한다고 할 때, 그 타입의 하위 타입도 문제없이 정상적으로 작동을 해야 한다는 것입니다.
리스코프 치환 원칙이 제대로 지켜지지 않으면 다형성에 기반한 개방 폐쇄 원칙 역시 위반하는 것이기 때문에 리스코프 치환 원칙을 지키는 것이 중요합니다.
C/C++ 예제
class Rectangle
{
protected:
int width, height;
public:
Rectangle(const int width, const int height)
: width{ width }, height{ height } { }
int get_width() const { return width; }
virtual void set_width(const int width) { this->width = width; }
int get_height() const { return height; }
virtual void set_height(const int height) { this->height = height; }
int area() const { return width * height; }
};
class Square : public Rectangle
{
public:
Square(int size) : Rectangle(size, size) {}
void set_width(const int width) override {
this->width = height = width;
}
void set_height(const int height) override {
this->height = width = height;
}
};
void process(Rectangle& r)
{
int w = r.get_width();
r.set_height(10);
}
int main()
{
Rectangle r{ 5,5 };
process(r);
Square s{ 5 };
process(s);
getchar();
return 0;
}
결과
expected area = 50, got 50
expected area = 50, got 100
LSP를 위반하는 전형적인 예로, 너비와 높이의 조회(getter) 및 할당(setter) 메서드를 가진 직사각형 클래스로부터 정사각형 클래스를 파생하는 경우를 들 수 있다.
정사각형 클래스는 항상 너비와 높이가 같다고 간주할 수 있다.
정사각형 객체가 직사각형을 다루는 문맥에서 사용되는 경우, 정사각형의 크기는 독립적으로 변경할 수 없기 때문에 (혹은 그래서는 안되기 때문에) 예기치 못한 행동을 하게 된다. 이 문제는 고치기 쉽지 않다.
정사각형 클래스의 할당 메서드를 수정하여 정사각형의 불변 조건(즉, 너비와 높이가 같음)을 유지하면, 이 메서드는 크기를 독립적으로 변경할 수 있다고 설명한 직사각형의 할당자의 사후조건을 무력화(위반)한다.
이러한 LSP 위반은 실전에서는 LSP를 위반한 클래스를 사용하는 코드가 실제로 기대하는 사후 조건이나 불변 조건에 따라 문제가 될 수도 있고 아닐수도 있다. 여기서 중요한 사안은 가변성이다. 정사각형과 직사각형이 조회 메서드만 가진다면 (즉, 이들이 불변객체라면), LSP 위반을 발생하지 않는다.
'Etc > Design Pattern' 카테고리의 다른 글
개방-폐쇄 원칙(Open/Closed Principle) (0) | 2021.12.06 |
---|---|
단일 책임 원칙(Single responsibility principle) (0) | 2021.11.30 |
객체 지향 설계(SOLID) (0) | 2021.11.26 |