Design Patterns2008. 5. 13. 18:49

객체지향 설계 원칙 5-2 LSP (Liskov Substitution Principle) 리스코프 대체 원칙


이번에는 리스코프 대체 원칙이다. 이 원칙은 Base-Class 와 Sub-Class 와의 관계에 대한 원칙이다.
이것을 먼저 한마디로 표현하면 다음과 같다.

"기반 타입은 서브타입을 대신 할수 있어야 한다."

말로 풀어서 설명하기는 자신이 없다. Exception 클래스를 예제로 설명해 보겠다.

사용자 삽입 이미지[그림 1]

 


[그림 1] 클 간단한 클래스 구성도 이다. 그럼 이것을 코드로 구현하면 [그림 2]가 된다.


 

 


[그림 2] 의 코드에서 try 부분에서 예외가 발생하면 어떻게 되겠는가 ?
"int* n = new int;" 는 메모리 생성에 대한 부분이므로 이부분에서 오류가 생기면 MemoryExecption 이 발생한다. 그리고 메모리 관련이외의 예외가 발생하면 CExecptoin 에서 catch 할 것이다.

그럼 [그림 2]의 코드에서 메모리 관련 예외를 catch 하는 부분을 제거 한다면 어떻게 되겠는가 ?
그러면 [그림 3]과 같이 코드가 구성될 것이다.

사용자 삽입 이미지[그림 3]


[그림 3] 코드에서 메모리 관련 예외가 발생하면 어떻게 되겠는가 ? CExecption 이 catch 에서 받아 처리 할것이다.

이 예는 기반타입(CExecption) 이 서브타입(CMemoryExecption) 을 대체하는 좋은 예이다.
서브타입을 설계할때 기반타입의 규칙을 잘 이해하여 설계해서 만들어야 하고, 후에 서브타입에 새로운 기능이 추가 될때 이를 기반타입에서도 처리할 수 있어야 한다.  다시말해, 기반 타입은 서브타입의 조건(서브타입의 조건을 포함)보다 더 많은 조건을 처리 할수 있어야 한다.
쉽게 그림으로 보면 [그림 4]와 같은 형태과 되어야 한다는 것이다.

사용자 삽입 이미지[그림 4]



그러면 여기서 한가지 의문을 가질수 있다. "서브타입의 모든 기능을 기반타입에서 소화 한다면, 왜 상속을 받아서 서브타입을 설계해야 하는가 ?" 라는 문제이다. 이 답을 하기전에 좋은 말 하나 먼저 들어보자.

"기반클래스 에서는 서브클래스에서 보다 사전 조건이 더 강해야 하고 사후 조건에서는 서브클래스에서 보다 약해야 한다."

무슨 말인지 감이 안온다. 먼저 사전 조건이란 위에서 Execption 의 예로 설명한 조건으로 생각해도 되겟다. CExecptoin 이 CMemoryExecption 보다 더 많은 예외를 잡아 낼수 있다. 이것은 사전 조건이 더 강하다. 라고 이해 하면 되겠다. 그럼 사후 조건에 대해서 한번 살펴 보자.

CExecption 과 CMemoryExecption 이 가지고 있는 char* ReportError() 메소드를 살표보자.

먼저 CExecption 의 ReportError 메소드를 호출하면 그 결과가 다음과 같다고 가정하자.
"[Error Code: 1234] [Error FileName] Test.cpp"
그리고 CMemoryExecptoin 에서 ReportError 메소드를 호출하면 그 결과과 다음과 같다고 가정하자.
"[Error Code: 1234] [Error FileName] Test.cpp [Error Memory Address] 0x12345678"

먼가 느낌이 오는가 ? 안온다면 [Error Memory Address] 부분에 집중해보자.
CExecption 의 ReportError 메소드에서 [Error Memory Address] 정보를 보여줄 책임이 있는가 ?
그렇지 않다 CExecption 에서는 [Error Memory Address] 대해서 알지 못한다. 그러면 CMemoryExecption 의 ReportError 메소드에서는 [Error Memory Address] 정보를 보여줄 책임이 있는가 ? 맞다. 책임이 있다.
이것을 어렵게 말하면 사후조건은 서브클래스(CMemoryExecption )가 기반클래스(CExecption ) 보다 강하다고 한다.

개인적으로 5원칙 중에 LSP 가 개념적으로 제일 어렵다. "왜 그럴까 ?" 생각해 봤는데 기존에 알고 사용했던 것과 많이 달라서 인거 같다. 이전에 클래스 상속관계에 대한 가이드는 IS-A 관계였다. 그래서 보통 서브클래스를 설계할때 기반클래스의 특징을 가지지만 더 확장하는 개념으로 많이 사용했었던거 같다. 앞으로 서브클래스 설계할때 LSP가 잘 지켜질지 의문이다.

"원칙은 원칙일뿐 현재 상황에서 최선이라고 생각하는 자신만의 원칙을 만들어 가자" ㅡㅡ

 

Posted by 상현달