본문 바로가기

기타/객체지향의 탄생(2013)

객체지향의 탄생-LSP

 

  1. LSP(Liskov Substitution Principle)

자식 타입들은 부모 타입들이 사용되는 곳에 대체될 수 있어야 한다. 초창기 자바 개발자일때 이 규칙을 잘 모른 상태에서 상속과 폴리모피즘을 어설프게 적용한적이있다. 이 규칙을 확실히 이해했다면 개발할때 해매는것이 아니라 더 깔끔하게 개발했을 것이다. 지금까지 무수히 강조했던 상속과 폴리모피즘을 명확하게 적용하고 싶을때 곰곰히 곱씹어야할 중요한 원칙이다.

 

LSP와 연결되는 개념인 상속과 폴리모피즘의 전형적인 구조는 다음과 같다.

 

[상속과 폴리모피즘의 전형적인 구조 그림]

 

이런 구조는 클라이언트가 하위 클래스가 아닌 상위 클래스나 인터페이스에 의존하고 클라이언트를 실행하는 런쳐 클래스에서 클라이언트 객체를 생성하면서 하위클래스를 넘겨주는 구조로 폴리모피즘을 구현하게 되어 있다.

 

여기서 중요한 점은 클라이언트 객체는 상위 클래스에 의존하기 때문에 상위 클래스의 명세만 알수 있다는 것이다. 만약 하위 클래스에 상위 클래스에는 없는 기능이 추가되었다면 특별히 하위 클래스를 직접 의존하지 않는한 클라이언트는 하위 클래스의 새로운 기능을 알수가 없다.

 

[LSP 위반 사례]

 

위의 클래스 구성도를 보면 [하위 클래스]가 [상위 클래스]처럼 사용될때 오버라이드된 메소드가 다른 의미를 가져와서 LSP와 어긋나는 것으로 보인다

 

가상으로, 유닉스 OS를 참고로 맥OS를 개발한다고 구상했을 때 위와 같은 상속 구성으로 했을 때 문제가 없을지 살펴보자. 어느 OS나 커널이 있어야 하고, 응용 프로그램이 있어야 하나 파라미터가 다르다면, 맥OS가 유닉스OS를 상속받는 것은 쓸데 없는 메소드도 상속받는 것이다.

 

위의 경우 유닉스OS의 응용프로그램(GCC)와 파일시스템(EXT3)같이 전혀 안 쓰일 메소드도 상속받게 된다.

 

이와 같이 하면 전형적인 상속의 오용케이스이며 이렇게 사용할 바에는 아예 별도의 클래스로 분리하는게 날지도 모른다. 이런 경우에는 몇가지 연결 방법으로 대체하여 깔끔하게 재편할 수 있다.

 

위의 그림처럼 위임으로 맥OS가 윈도우OS 객체를 속성으로 갖고 있고, 커널() 등의 메소드에서 먼저 또는 나중에 윈도우 OS의 커널() 메소드를 호출하고 맥OS에 알맞은 로직을 따로 구현할 수 있다.

 

이제 궁금한 것은 상속, 위임, 구성, 집합중 위임을 어느때 사용할것이냐이다. 위임이나 구성이나 집합이나 어느때 써야 되는지 애매하고 햇갈린다. 위임은 다른 클래스의 기능을 사용해야 하지만 그 기능을 변경할 필요가 없을때 사용한다.

 

위임은 위임하고 있는 객체 기능의 로직이 변하지 않는다. 만약 위임하고 있는 클래스의 기능을 다른 기능으로 교체하고 싶을때는 구성을 쓴다.

 

위와 같이 구성을 활용하면, 맥 OS 구현시 참고하고 싶은 OS를 자유자재로 교체할 수 있다. 쓰고 싶은 기능의 로직을 자유롭게 교체할수 있기 때문에 유연하고 확장성이 높다.

 

위의 그림은 여지껏 무수히 많이 설명했던 전형적인 구성 그림이다. 클라이언트 객체는 인터페이스에 의존하였다가 쓰고 싶은 기능을 취사선택하여 얼마든지 변경하거나 확장하여 쓸수 있다. 특히 컴파일 단계가 아닌 실행 단계에 자유롭게 여러 구현 클래스중 하나를 선택하여 쓸수 있으므로 유연하고 강력하다. 구성을 통해 하나의 인터페이스를 구현한 여러 클래스들의 기능을 취사선택할수 있고 실행중에 그 클래스를 바꾸어 기능을 변경할 수 있다.

 

구성의 특징은 클라이언트가 구성으로 조합된 객체들을 소유하고 있다는 것이다. 클라이언트 객체가 없어지면 소유하고 있던 모든 기능들도 같이 없어진다. 구성에 참여한 객체들은 그 클라이언트 객체의 외부에는 존재하지 않는다.

 

여기서 구성과 집합의 차이점을 발견한다. 집합은 하나의 조합된 객체 패밀리들이 어느 클라이언트 객체의 부분으로 사용되지만 다른 외부 세계 클라이언트 객체도 사용할때 집합으로 맺어진다. 이 차이점만 명심하면 구성과 집합에 굳이 눈 부릎뜨고 따지지 않고 효과적으로 상속을 대체하면서 자식 타입들은 부모 타입들이 사용되는 곳에 대체할 수 있다.

 

자식 타입들은 부모 타입들이 사용되는 곳에 대체된다는 규칙을 지킬때 상속을 사용할 경우 상속의 효과를 확실히 누린다.

 

이 규칙을 만족하지 못한다면 상속을 대체할 더 강력한 위임이나 구성, 집합을 사용할 수 있다. 이 연결관계를 명확히 알고 자유자재로 사용할때 객체지향의 객체 설계의 묘미를 알게되며 디자인 패턴을 익히기전 튼튼한 기초를 다지게 될 것이다.

 

LSP 규칙 이해를 바탕으로 상속을 쓸것이냐, 위임, 구성, 집합을 쓸것이냐 결정할 수 있다.

 

덧 ) 이 객체지향의 탄생 원고는 제가 책으로 내려다가 일단 잘 안되었는데요. 이유는 비문이 많다. 단락내 주제가 중복된다. 어떤 상황 설명을 과장한다.등 입니다. 그래도 원고를 일단 블로그에 몽땅 풀어보고 언젠가 제대로 교정해서 다시 도전할 생각입니다. 비문이 많다. 단락내 주제가 중복된다. 어떤 상황 설명을 과장한다. 이점을 감안해서 읽고 객체지향을 이해하는데 도움이 되셨으면 좋겠습니다. 의견도 주셨으면 좋겠습니다. 원고 조금만 교정하면 괜찮을것 같은 출판사 관계자분의 피드백도 환영합니다. 특별한 일 없으면 매주 월수 발행 예정입니다.