이번에는 세 번째 원칙인 리스코프 치환 원칙(LSP)에 대해서 알아보도록 하겠습니다.
리스코프 치환 원칙(LSP)의 이해와 예제
리스코프 치환 원칙이란
자료형 B가 자료형 A의 서브타입라면 필요한 프로그램의 속성(정확성, 수행하는 업무 등)의 변경 없이 자료형 B의 객체를 자료형 A의 객체로 교체(치환)할 수 있어야 한다는 원칙입니다.
2023.01.14 - [개발/개발 공통] - [객체 지향] SOLID 원칙에 대해서 알아보자
즉 베이스로 만들어진 Super 클래스 대신에 상속받은 하위 클래스를 사용할 수 있어야 하고 잘 동작해야 합니다.
예제
이번에는 새의 경우를 예를 들어 보겠습니다.
아래와 같이 Bird 라는 클래스의 fly라는 메서드가 있습니다. eagle과 chicken은 모두 Bird에 해당하므로 언뜻 보면 상속이 가능할 것입니다.
하지만 fly라는 동작을 수행했을 때 eagle은 문제가 없지만 chicken은 수행할 수 없습니다. 닭은 날 수 없으니깐요.
따라서 이러한 상황은 리스코프 치환 원칙(LSP)에 어긋난다고 볼 수 있습니다.
#include <iostream>
using namespace std;
class Bird
{
virtual string fly() = 0;
};
class eagle : public Bird
{
string fly() override
{
return "fly!";
}
};
class chicken : public Bird
{
string fly() override
{
return "can't fly!"; //Error
}
};
개선하기 위해서 저는 Bird 클래스를 두 가지로 분리했습니다. 하나는 BirdCanFly, 하나는 BirdCanNotFly입니다.
기존 eagle의 경우에는 BirdCanFly를 상속하면 되고 chicken의 경우 BirdCanNotFly를 상속하면 됩니다.
만약 penguin 클래스가 추가된다고 하면 BirdCanNotFly를 상속함으로써 명확히 사용할 수 있을 것입니다.
#include <iostream>
using namespace std;
class BirdCanFly
{
virtual string fly()
{
return "fly!";
}
};
class BirdCanNotFly
{
virtual string fly()
{
return "can't fly!";
}
};
class eagle : public BirdCanFly
{
string fly() override
{
return "fly!";
}
};
class chicken : public BirdCanNotFly
{
string fly() override
{
return "can't fly!"; //Error
}
};
class penguin : public BirdCanNotFly
{
string fly() override
{
return "can't fly!"; //Error
}
};
결론
리스코프 치환 원칙은 당연한 듯하면서도 자칫 어기기 쉬운 원칙입니다. 위의 예시처럼 직관적으로 기능을 분리할 수 있을 때는 쉽게 이해가 가지만 추상적인 객체나 개념을 구현한 코드의 경우 리스코프 치환 원칙을 잘 생각해서 구현해야 할 것입니다.
'개발 > 개발 공통' 카테고리의 다른 글
[객체지향 SOLID 원칙] 의존성 역전 원칙(DIP)의 이해와 예제 (0) | 2023.05.26 |
---|---|
[객체지향 SOLID 원칙] 인터페이스 분리 원칙(ISP)의 이해와 예제 (0) | 2023.05.26 |
[객체지향 SOLID 원칙] 개방 폐쇄 원칙(OCP)의 이해와 예제 (0) | 2023.05.26 |
[객체지향 SOLID 원칙] 단일 책임 원칙(SRP)의 이해와 예제 (0) | 2023.05.26 |
좋은 코드 개발 문화 (클린 코드, 코드 리뷰, TDD) (0) | 2023.05.22 |