본문으로 바로가기

더 진행하기 전에 인터페이스와 베이스 클래스의 차이점을 함 생각해보도록 하자. 객체 지향 설계에 익숙하지 않는 개발자는 타입을 설계할때 인터페이스를 사용해야 할지 아니면 클래스를 사용해야 할지를 구분하지 못한다. 이곳에서 나름대로의 기준을 정리해보고자 한다.

상속을 좀 더  자세히 살펴보자. 그럼 상속에는 성격이 좀 다른 상속들이 존재하는 것을 알 수 있다. 어떤 경우는 데이터를 중심으로 해서 상속관계를 생각하는 경우가 있다. 이 경우는 "객체가 내부적으로 어떻게 동작하는가"에 포커스를 두는 것이다. 부모 객체는 자식에 공통적인 데이터를 가지고 있도록 하고 자식 타입에서 자신만의 특별한 데이터를 추가하도록 설계한다면 바로 데이터를 중심의 상속을 설계하고 있는것이다.

그러나 어떤 경우는 기능 중심으로 해서 상속관계를 생각하는 경우가 있다. 이 경우는 "무엇을 하는가"와 관련되어 있다. 즉 내부적으로 어떤 데이터가 어떻게 사용되는지에 관심있기 보다는 메소드, 속성, 이벤트, 인덱서 같은 외부에 드러나는 함수 멤버들이 더 관심있는 경우이다. 앞의 로거 객체의 상속을 한 번 더 생각해 보자. 어떤 로거라도 저장소에 메세지를 쓰는 Write()는 공통적으로 있을 것이다. 각각 내부적으로 사용하는 데이터는 관심없다. 무슨 데이터를 어떻게 사용하든 상관없다. 모든 자식들에서 메세지를 저장소에 쓰는 Write()라는 메소드를 나름대로 구현하기만 하면 된다.
타입을 설계하다보면 이 두가지 관점의 사고를 해야 하는 경우가 함께 존재하기도 하지만 그러나 경우에 따라서는 자식 타입에서 기능적인 측면('어떤 일을 할 수 있어야 한다')만을 고려하는 설계를 하는 경우도 많이 있다. 이런 경우 인터페이스를 사용하면 된다.

인터페이스를 다른 식으로 설명하면 일종의 계약(contract)이다. "이 메소드는 어떤 일을 한다. 시그너쳐 즉 인자는 어떤 의미가 있고 리턴 값은 어떤 의미가 있다. 그러니까 이것을 구현하는 자식 클래스(또는 개발자)는 그 의미를 알고 그에 맞게 구현해야 한다."는 뜻을 포함하고 있다. 즉 인터페이스는 단순한 표현상의 계약(시그너쳐) 뿐만 아니라 로직상의 의미도 포함하고 있는 것이다. 자식 타입에서는 문법적인 시그너쳐에만 맞도록 메소드를 정의하는 것이 아니라 비즈니스 로직상 그 메소드에서 해야 할 일을 하도록 구현해야 한다는 것이다. 따라서 인터페이스를 구현하는 개발자는 준수해야 할 그 시그너쳐도 알아야 하지만, 그것보다는 그 인터페이스에서 수행해야 할 로직상의 기능에 대해서도 알고 있어야 한다는 것이다.
만약 설계시 고려해야 하는 것이 데이터간의 상속관계라면 클래스를 이용해서 구현하면 된다. 데이터와 기능을 고려한 상속 관계를 설계해야 하는 경우도 클래스를 사용하면 된다.
인터페이스는 외부와 약속된 API만을 정의하는 타입이므로 그것을 실제로 구현하는 것은 클래스여야 한다.

잘 설명하고 있나 모르것네. 객체 지향을 해온지가 10년이 넘었는데도 설명하려면 아직 부족한 감을 느낀다.  쓰으~~


댓글을 달아 주세요

  1. 오정환 2009.12.11 11:00

    명쾌한 설명 입니다.

  2. VSTO 2011.07.02 11:17

    좋은 글 감사합니다.

  3. 오차진 2012.05.04 10:38

    정확한 설명 감사합니다. 이해하고 있는 줄은 모르겠지만ㅠㅠ