리스코프 치환 원칙(LSP)

들어가며 

 

지금까지 객체지향 설계 원칙 SOLID 중에 'L'인 리스코프 치환 원칙(LSP, Liskov Substitution Principle)에 대해 의미를

부모클래스와 자식클래스간 서로 치환, 즉 캐스팅될 수 있어야한다는 의미로만 이해하고 있었다.

누가 리스코프 치환원칙에 대해 물어보면 자세히 설명을 해줄 수 있을까?

앞서 말한 의미의 이유까지는 설명 할 수 없을것 같았다.

다른 원칙들은 여러 개발서적, 실제 개발을 통해서 깊은 이해를 할 수 있었지만 리스코프 치환원칙은 개념적 이해가 부족한감이 들어 정리하고자 한다.

 

 

왜 리스코프인가?

 

리스코프 치환 원칙은 MIT 컴퓨터 공학과 리스코프 교수가 제안한 원칙이라 교수의 이름을 따서 불리는것으로 보인다.

 

 

리스코프 원칙의 정의

 

리스코프 교수가 제안한 원칙의 내용은 다음과 같다.

 

일반화 관계에 대한 내용을 이야기하며 자식 클래스는 
최소한 자신의 부모 클래스에서 가능한 행위는 수행할 수 있어야한다.

 

즉, 부모클래스와 자식 클래스 사이의 행위가 일관성이 있어야 한다는 의미다.

 

더 풀어서 얘기해보면 일반화 관계는 'is a kind of 관계' 라고도 한다. 예를들어 '원숭이 is a kind of 포유류' 는 성립된다.

그러나 '오리너구리 is a kind of 포유류' 는 성립될까?

 

포유류의 정의를 살펴보자.

- 포유류는 새끼를 낳아 번식한다.

- 포유류는 털이나 두꺼운 피부로 덮여 있다.

 

이를 원숭이에 대입해보면 다음과 같다.

- 원숭이는 새끼를 낳아 번식한다.

- 원숭이는 털이나 두꺼운 피부로 덮여 있다.

 

하지만 오리너구리는 새끼가 아닌 알을 낳는다.

- 오리너구리는 알을 낳아 번식한다.

- 오리너구리는 털이나 두꺼운 피부로 덮여 있다.

 

그러나 오리너구리는 젖을 먹여 기르는등 포유류와 유사한점을 지니기 때문에 포유류로 분류되지만 리스코프 치환 원칙 관점에서는 일관성이 위배되는것으로 볼 수 있다.

 

 

클래스 관점에서는 어떻게 이야기할 수 있을까?

 

앞서 얘기했던 "부모클래스와 자식 클래스 사이의 행위가 일관성이 있어야 한다는 의미다." 라는 말을 되새겨 보자.

일관성, 즉 LSP을 위반하지 않기 위해서는 부모클래스에서 구현된 메서드는 자식클래스에서 오버라이딩하여 재구현 하지 않아야한다.

(단, 부모클래스에서 정의한 추상메서드를 자식클래스에서 오버라이딩하여 구현하는것은 문제없다, 추상화와는 별개)

 

자식클래스에서 오버라이딩시 자식클래스와 부모클래스 메서드 각 호출하면 결국 일관성있는 결과가 아닌 서로 다른 결과가 나온다.

다시 말해 자식클래스에서 오버라이딩하여 부모클래스에서 구현된 메서드를 재정의하는 행위는 부모클래스의 책임을 무시하는 행위이고 일관성 또한 위반하는 행위이다.

 

마지막으로 리스코프 교수가 정의한 내용에 대해 다시 보자

 

일반화 관계에 대한 내용을 이야기하며 자식 클래스는 
최소한 자신의 부모 클래스에서 가능한 행위는 수행할 수 있어야한다.