245. LSP (Liskov Substitution Principle) - 리스코프 치환 원칙 SOLID 상속 다형성 하위 클래스 계약 위반 오버라이딩 부모 타입
핵심 인사이트: (객체지향 상속의 치명적 독, L) '새(Bird)'라는 부모 클래스가 있다. 기능은
fly() (날다)다. 멍청한 개발자가 '펭귄'을 만들려는데, 코딩하기 귀찮아서 그냥 '새'를 상속(extends)받아버렸다. 근데 펭귄은 못 난다! 그래서 펭귄의fly()함수를 오버라이딩(재정의)해서 속에다가throw new Exception("난 못 날아 ㅆㅂ!")이라고 에러를 터뜨리게 짜놨다. 다음 날, 시스템이 뻗었다.List<새> birds에 든 모든 새를 한 마리씩 꺼내서fly()시켰는데, 펭귄이 튀어나와 에러를 뿜으며 하늘에서 추락한 것이다!! 바바라 리스코프 교수가 소리친다. "야 ㅆㅂ!! 상속(Inheritance)이 코드 재사용하라고 있는 꿀통인 줄 알아?! '부모(새)' 자리에 '자식(펭귄)'을 100% 그대로 교체해서 집어넣었을 때(치환), 부모가 원래 하던 약속(날아야 함)을 자식이 1%라도 어기고 에러를 뿜으면 그건 호적을 파버려야 할 가짜 상속이야!! 자식은 하늘이 두 쪽 나도 부모의 원래 행동 규약(계약)을 100% 완벽히 지켜내는 놈들만 호적(상속)에 올려라!!" 다형성의 무기를 휘두를 자격을 심사하는 가장 날카로운 족보 감별사, 리스코프 치환 원칙(LSP)이다.
Ⅰ. 상속(Inheritance)의 달콤한 유혹과 비극
- 초보 개발자들은 "오! 부모 클래스에 함수 10개 있네? 나 이거 복사하기 귀찮으니까 그냥
extends상속받아서 10개 공짜로 써야지~"라고 생각합니다. - 비극의 시작: 10개 중 1개가 내(자식) 입맛에 안 맞습니다. 그래서 그 함수 1개를 **'에러를 뿜게 덮어쓰거나(오버라이딩), 아예 비워두거나, 부모와 완전히 다른 짓을 하게 개조'**해버립니다.
- 시스템(클라이언트 코드)은 부모인 줄 믿고 그 1번 함수를 호출했다가, 자식이 튀어나와서 딴짓을 하거나 에러를 뿜어 프로그램이 대폭발합니다.
Ⅱ. LSP (Liskov Substitution Principle)의 개념 🌟
- 1988년 컴퓨터 과학자 바바라 리스코프(Barbara Liskov) 교수가 발표한 상속의 절대 헌법.
- 개념: 컴퓨터 프로그램에서 부모 클래스의 인스턴스(객체)를 사용하는 곳에, 그 부모를 상속받은 '자식 클래스의 인스턴스'를 대신 교체(치환 Substitution)해서 집어넣더라도, 프로그램의 정확성(부모가 맺어둔 계약)을 단 1%도 깨뜨리지 않고 완벽하게 똑같이 정상 동작해야만 올바른 상속 관계라는 원칙입니다.
Ⅲ. 유명한 LSP 위반 사례: '직사각형과 정사각형' 🌟 핵심 기출 🌟
가장 유명한 교과서 예제입니다.
1. 상식의 배신 (가짜 상속)
- 수학 시간에 "정사각형은 직사각형의 한 종류다(is-a)"라고 배웠습니다.
- 그래서 개발자는
직사각형(부모)을 상속받아정사각형(자식)클래스를 만들었습니다. - 부모의 계약: 직사각형은
set가로(5),set세로(10)을 하면 면적이50이 되어야 합니다. - 자식의 깽판: 정사각형은 가로세로가 무조건 같아야 하죠? 그래서 자식(정사각형) 클래스는
set가로(5)를 호출하면, 지 맘대로 **'세로도 강제로 5'**로 같이 바꿔버리도록 함수를 오버라이딩(개조)해 놨습니다.
2. 치환(Substitution)의 끔찍한 폭발
- 시스템(클라이언트)은 저 객체가 직사각형(부모)인 줄 알고 찰떡같이 믿고 있습니다.
- "오, 직사각형이네?
set가로(5),set세로(10)! 그럼 면적은 당연히50이겠지?" - 결과:
정사각형(자식)이 부모 자리에 몰래 숨어 들어와 치환되어 있었습니다! 시스템이set세로(10)을 부르는 순간, 정사각형 놈은 지 맘대로 가로까지 10으로 같이 엎어버렸고, 면적은100이 튀어나옵니다. - 사형!: 부모가 약속했던 행동 계약("가로세로 독립 조작")을 자식이 맘대로 깨버렸으므로, 프로그램은 에러를 뿜고 죽어버립니다. 수학적으로는 직사각형이 정사각형의 부모일지 몰라도, **객체지향의 세계(LSP)에서는 이 둘을 상속 관계로 묶는 순간 코드가 터지는 최악의 가짜 상속(LSP 위반)**이 됩니다.
Ⅳ. 어떻게 해결할까? (다형성의 수호자)
- 해결책은 간단합니다. 펭귄은 새를 상속받으면 안 됩니다.
- 펭귄과 독수리의 진짜 공통점은 '새'가 아니라 **'동물(Animal)'**입니다. 둘을 공통의 부모(인터페이스)인
동물로 묶고, 독수리에게만Flyable(날 수 있는)인터페이스를 따로 붙여줘야(상속의 분리) LSP가 완벽히 지켜지고 시스템이 평화로워집니다.
📢 섹션 요약 비유: **리스코프 치환 원칙(LSP)**은 패스트푸드점 주방의 **'가짜 아르바이트생 대타 쓰기(치환) 금지법'**입니다. 주방에 원래 **'감자튀김 튀기는 달인(부모 클래스)'**이 있었습니다. 이 달인의 계약(기능)은 "감자를 주면 3분 뒤에 튀김을 내놓는다"입니다. 어느 날 달인이 아파서, 그의 **'아들(자식 클래스)'**을 대타로 주방에 세웠습니다(치환 Substitution). 점장(시스템)은 당연히 아들이 아버지의 피를 물려받았으니(상속) 똑같은 계약을 지킬 줄 알고 감자를 줬습니다. 그런데 이 미친 아들이 감자를 받더니 튀김기가 아니라 믹서기에 넣고 **'감자 주스'**를 갈아버렸습니다!(자식의 함수 오버라이딩 깽판). 점장이 튀김인 줄 알고 손님에게 나갔다가 식당이 문을 닫습니다. 바바라 리스코프 교수는 소리칩니다. "야! 아버지 자리에 아들을 대타(치환)로 세울 거면, 아들이 아버지보다 감자튀김을 더 바삭하게(기능 추가) 튀기는 건 합법이지만, 감자로 주스를 갈아버리거나(부모의 계약 위반) '저 튀길 줄 모르는데요?(에러 예외 발생)'라고 배째라 시전하는 놈은 절대 아버지를 상속받은 자식으로 호적에 올리지 마라!!" 다형성이라는 이름으로 부모의 믿음을 배신하는 가짜 상속 자식들을 호적 파버려, 프로그램이 예기치 않게 터지는 나비효과를 원천 봉쇄하는 객체지향 족보의 가장 날카로운 판별법입니다.