객체지향의 사실과 오해

3. 타입과 추상화

Featured image

추상화란 다음과 같이 정의할 수 있다.

어떤 양상, 세부 사항, 구조를 좀 더 명확하게 이해하기 위해 특정 절차나 물체를 의도적으로 생략하거나 감춤으로써 복잡도를 극복하는 방법
복잡성을 다루기 위해 추상화는 두 차원에서 이뤄진다.

  1. 구체적인 사물들 간의 공통점은 취하고 차이점은 버리는 일반화를 통해 단순하게 만드는 것
  2. 중요한 부분을 강조하기 위해 불필요한 세부 사항을 제거함으로써 단순하게 만드는 것

객체지향 패러타임에서 객체는 명확한 경계를 가지고 서로 구별할 수 있는 구체적인 사람이나 사물이라고 정의한다.

객체지향 패러다임은 객체라는 추상화를 통해 현실의 복잡성을 극복한다.

객체지향 패러다임을 이용해 유용하고 아름다운 애플리케이션을 개발하기 위한 첫걸음은 추상화의 두 차원을 올바르게 이해하고 적용하는 것이다.

객체지향과 추상화

개념

개념이란 추상화의 일종으로, 객체지향 패러다임에서는 구체적이고 실제적인 객체가 존재하는데 이런 수많은 객체들의 공통적인 특성을 기준으로 객체를 여러 그룹으로 묶어 상황을 단순화하려고 한다.
이처럼, 공통점을 기반으로 객체들을 묶기 위한 그릇을 개념(concept)이라 한다.

개념이란, 일반적으로 우리가 인식하고 있는 다양한 사물이나 객체에 적용할 수 있는 아이디어나 관념을 뜻한다.

개념을 이용하면 객체를 여러 그룹으로 분류(classification)할 수 있다.

결국 각 객체는 특정한 개념을 표현하는 그룹의 일원으로 포함된다. 이처럼 객체에 어떤 개념을 적용하는 것이 가능해서 개념 그룹의 일원이 될 때 객체를 그 개념의 인스턴스(instance)라고 한다.

객체란, 특정한 개념을 적용할 수 있는 구체적인 사물을 의미한다.

개념의 세 가지 관점

객체를 분류하기 위한 틀

분류란, 객체에 특정한 개념을 적용하는 작업이다. 객체에 특정한 개념을 적용하기로 결심했을 때 우리는 그 객체를 특정한 집합의 멤버로 분류하고 있는 것이다.

객체를 어떤 개념으로 분류할지에 따라 객체지향의 품질이 결정된다. 객체를 적절한 개념에 따라 분류하지 못한 애플리케이션은 유지보수가 어렵고 변화에 쉽게 대처하지 못한다.
따라서, 객체는 최대한 직관적으로 분류하는 것이 좋다.

분류는 추상화를 위한 도구이다.

개념은 객체들의 복잡성을 극복하기 위한 추상화 도구다. 추상화를 사용함으로써 복잡한 세상을 그나마 제어 가능한 수준으로 단순화 할 수 있다.

타입

타입은 개념이다.

타입의 정의는 개념과 동일하다. 하지만 근본적인 개념은 동일하더라도 컴퓨터 내부로 들어가면 기계적인 의미로 윤색된다.

데이터 타입

타입 시스템의 목적은 데이터가 잘못 사용되지 않도록 제약사항을 부과하는 것이다.

데이터 타입은 메모리 안에서 저장된 데이터의 종류를 분류하는 데 사용하는 메모리 집합에 관한 메타데이터다. 데이터에 대한 분류는 암시적으로 어떤 종류의 연산이 해당 데이터에 대해 수행될 수 있는지를 결정한다.

객체와 타입

객체지향 패러다임에서 객체는 일종의 데이터 타입과 같이 사용된다. 따라서 객체를 타입에 따라 분류하고 그 타입에 이름을 붙이는 것은 결국 프로그램에서 사용할 새로운 데이터 타입을 선언하는 것과 같다.

그렇다고 객체가 데이터는 아니다. 객체는 행동에 따라 상태가 결정되는 관계이다. 따라서 객체가 협력을 위해 어떤 책임을 지녀야 하는지를 결정하는 것이 객체지향 설계의 핵심이다.

따라서 데이터 타입의 두 조건과 같이 객체에도 이것이 해당된다.

  1. 어떤 객체가 어떤 타입에 속하는 지를 결정하는 것은 객체가 수행하는 행동이다. 어떤 객체들이 동일한 행동을 수행할 수 있다면, 그 객체들은 동일한 타입으로 분류될 수 있다.
  2. 객체의 내부적인 표현은 외부로부터 철저하게 감춰진다. 객체의 행동을 효과적으로 수행할 수만 있다면 객체 내부의 상태를 어떤 방식으로 표현하더라도 무방하다.

행동이 우선이다

객체의 타입은 객체가 어떤 행동을 하느냐에 따라 결정된다. 즉 행동이 객체의 타입을 결정하게 되고, 같은 타입에 속한 객체는 행동만 동일하다면 서로 다른 데이터를 가질 수 있다.
동일한 행동이란 동일한 책임을 의미하며, 동일한 책임이란 동일한 메시지 수신을 의미한다. 따라서 동일한 타입에 속한 객체는 내부의 데이터 표현 방식이 다르더라도 동일한 메시지를 수신하고 이를 처리할 수 있다.

다만, 내부의 표현 방식이 다르기 때문에 동일한 메시지를 처리하는 방식이 다를 수밖에 없는데 이를 다형성에 의미를 부여한다.

데이터의 내부 표현 방식과 무관하게 행동만이 고려 대상이라는 건 외부에 데이터를 감춰야 한다는 것을 의미한다. 훌륭한 객체지향 설계는 외부에 행동만을 제공하고 데이터는 행동 뒤로 감춰야 한다. 이를 캡슐화라고 한다.

행동에 따라 객체를 분류하기 위해서는 객체가 내부적으로 관리해야 하는 데이터가 아니라 객체가 외부에 제공해야 하는 행동을 먼저 생각해야 한다.
이를 위해 객체가 외부에 제공해야 하는 책임을 먼저 결정하고 그 책임을 수행하는 데 적합한 데이터를 나중에 결정한 후, 데이터를 책임을 수행하는 데 필요한 외부 인터페이스 뒤로 캡슐화해야 한다.

타입의 계층

일반화/특수화 관계

타입과 타입 사이에는 일반화/특수화 관계가 존재할 수 있다.(ex. 트럼프와 트럼프 인간)

중요한 것은 객체지향에서 일반화/특수화 관계를 결정하는 것은 역시 객체의 상태를 표현하는 데이터가 아닌 행동이다. 해당 객체의 행동이 얼마나 더 특수하게 행동하는지에 따라 결정된다.

정리해보면, 일반적인 타입은 특수한 타입에 비해 더 적은 수의 행동을 가지며 특수한 타입은 일반적인 타입에 비해 더 많은 행동을 가진다. 단, 특수한 타입은 일반적인 타입이 할 수 있는 모든 행동을 동일하게 수행할 수 있어야 한다.

정적 모델

타입의 목적

타입을 사용하는 이유는 인간의 인지 능력으로는 시간에 따라 동적으로 변하는 객체의 복잡성을 극복하기가 어렵기 때문이다.

따라서 타입을 추상화함으로써 동적으로 변하는 데이터에 집중하는 것이 아닌 수시로 변화할 수 있는 가능성에 집중하게 된다.

동적 / 정적 모델

스냅샷 : 객체가 특정 시점에 어떤 상태를 갖는냐

객체지향 애플리케이션을 설계하고 구현하기 위해서는 객체 관점의 동적 모델과 객체를 추상화한 타입 관점의 정적 모델을 적절히 혼용해야 한다.

클래스

객체지향 프로그래밍 언어에서 정적인 모델은 클래스를 이용해 구현된다. 따라서 타입을 구현하는 가장 보편적인 방법은 클래스를 이용하는 것이다.

클래스와 타입은 동일한 것이 아니다. 타입은 객체를 분류하기 위해 사용하는 개념이다. 반면 클래스는 단지 타입을 구현할 수 있는 여러 구현 메커니즘 중 하나일 뿐이다.

정리

객체를 분류하는 기준은 타입이며 타입을 나누는 기준은 객체가 수행하는 행동이다. 객체를 분류하기 위해 타입을 결정한 후 프로그래밍 언어를 이용해 타입을 구현할 수 있는 방법 중 하나가 클래스를 활용하는 것이다.

결국, 객체지향에서 가장 중요한 것은 동적으로 변하는 객체의 ‘상태’와 상태를 변형하는 ‘행위’다.