객체지향 설계 원칙 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가 잘 지켜질지 의문이다.
"원칙은 원칙일뿐 현재 상황에서 최선이라고 생각하는 자신만의 원칙을 만들어 가자" ㅡㅡ
'Design Patterns' 카테고리의 다른 글
객체지향 설계 원칙 5-5 ISP (Interface Segregation Principle) (2) | 2008.07.08 |
---|---|
객체지향 설계 원칙 5-4 DIP (Dependency Inversion Principle) (0) | 2008.06.28 |
객체지향 설계 원칙 5-3 SRP (Single Responsibility Principle) (0) | 2008.06.21 |
객체지향 설계 원칙 5-1 OCP(Open-Close Principle) (2) | 2008.05.06 |
객체지향 설계 원칙 5-0 시작 하며... (2) | 2008.05.01 |