[객체지향의 사실과 오해] 추상화 기법

추상화 기법의 종류

sonnie
lucky-sonnie
6 min readJul 8, 2020

--

  1. 분류와 인스턴스화
  2. 일반화와 특수화
  3. 집합과 분해
  1. 분류와 인스턴스화

개념과 범주

객체를 분류하고 범주로 묶는 것은 객체들의 특정 집합에 공통의 개념을 적용하는 것을 의미한다. 개념을 적용하는 과정을 분류라고 한다. 분류는 객체를 특정한 개념을 나타내는 집합의 구성 요소로 포함시킨다. (어떤 객체를 자동차라는 개념으로 분류하는 것은 자동차라는 개념을 적용할 수 있는 집합의 일원으로 해당 객체를 포함시키는 것을 의미한다.)

사람들은 분류를 통해 개별 현상을 하나의 개념으로 다룬다. 이때 ‘수많은 개별적인 현상들’을 객체라고 하고, ‘하나의 개념’을 타입이라고 한다. (분류는 객체를 타입과 연관시키는 것이다.) 분류의 역은 타입에 해당하는 객체를 생성하는 과정으로 인스턴스화 또는 예시라고 한다.

“타입 == 개념 == 속성과 행위가 유사한 객체에 공통적으로 적용되는 관념이나 생각 ”

한마디로 분류는 객체와 타입 간의 관계를 나타낸 것이다. 어떤 객체가 타입의 정의에 부합할 경우 그 객체는 해당 타입으로 분류되며 자동으로 타입의 인스턴스가 된다.

타입

타입을 객체의 분류 장치로 적용할 수 있으려면 세 가지 관점에서의 정의가 필요하다.

  • 심볼: 타입을 가리키는 간략한 이름이나 명칭
  • 내연: 타입의 완전한 정의. 내연의 의미를 이용해 객체가 타입에 속하는지 여부를 확인할 수 있다.
  • 외연: 타입에 속하는 모든 객체들의 집합

외연과 집합

타입의 외연은 타입에 속하는 객체들의 집합으로 표현한다. 집합은 외연을 가리키는 또 다른 명칭이다. 객체들은 동시에 서로 다른 집합에 포함될 수도 있다.

  • 단일 분류: 한 객체가 한 시점에 하나의 타입에만 속하는 것
  • 다중 분류: 한 객체가 한 시점에 여러 타입에 속하는 것

다중 분류와 다중 상속은 다르다. 다중 상속은 하나의 타입이 다수의 슈퍼타입을 가질 수 있도록 허용하지만, 타입 정의를 생략할 수는 없다. 다중 분류는 특정한 타입을 정의하지 않고도 하나의 객체가 서로 다른 타입의 인스턴스가 되도록 허용한다.

객체가 한 집합에서 다른 집합의 원소로 자신이 속하는 타입을 변경할 수 있는 경우 동적 분류라고 하며, 객체가 자신의 타입을 변경할 수 없는 경우에 정적 분류라고 한다.

대부분의 OOP 언어들은 단일 분류만을 지원한다. 따라서 다중 분류와 동적 분류를 구현하기는 어렵다. 하지만 다중 분류와 동적 분류 관점에서 도메인 모델의 초안을 만든 후, 단일 분류와 정적 분류 방식으로 구현하는 방법이 최선이다.

클래스

OOP를 이용해 타입을 구현하는 가장 보편적인 방법은 클래스를 이용하는 것이다. 이 외에도 abstract class, interface를 통해 구현할 수도 있다. 대부분의 OOP 언어에서 동일한 범주에 속하는 객체는 동일한 클래스의 인스턴스여야 한다.

2. 일반화와 특수화

범주의 계층

린네(1735년 ‘자연의 체계’를 발표한 학자)의 계층 구조는 좀 더 세부적인 범주가 계층의 하위에 위치하고 좀 더 일반적인 범주가 계층의 상위에 위치한다. 이때 계층의 상위에 위치한 범주를 계층의 하위에 위치한 범주의 일반화라고 하고, 계층의 하위에 위치한 범주는 계층의 상위에 위치한 범주의 특수화라고 한다.

서브타입

어떤 타입이 다른 타입보다 일반적이라면 이 타입을 슈퍼타입(supertype)이라고 하고, 어떤 타입이 다른 타입보다 더 특수하다면 이 타입을 서브타입(subtype)이라고 한다. 일반화와 특수화의 계층 구조에서 서브타입은 슈퍼타입이 가진 본질적인 속성과 함께 자신만의 추가적인 속성을 가진다.

상속

프로그래밍 언어를 이용해 일반화와 특수화 관계를 구현하는 가장 일반적인 방법은 클래스 간의 상속을 사용하는 것이다. 하지만 모든 상속 관계가 일반화 관계인 것은 아니다.

일반화의 원칙은 한 타입이 다른 타입의 서브타입이 되기 위해서는 슈퍼타입에 순응(conformance)해야 한다는 것이다. 순응에는 구조적인 순응(structural conformance)과 행위적인 순응(behavioral conformance)이 있다. 두 가지 모두 기대 집합에 대해 서브 타입의 슈퍼타입에 대한 대체 가능성을 의미한다.

  • 구조적인 순응의 기대 집합은 속성과 연관관계에 관한 것이다. 서브타입은 슈퍼타입이 가지고 있는 속성과 연관관계 면에서 100% 일치해야 한다.(내연과 관련된 100% 규칙 의미) Person이 name이라는 속성을 가진다면 Person의 서브타입인 Employee 역시 name이라는 속성을 가질 것이라고 기대한다. (Employee는 Person에 구조적으로 순응하기 때문에 Person을 대체할 수 있다.)
  • 행위적인 순응의 기대집합은 행위가 동일한 계약을 기반으로 하는지에 관한 것이다. 서브타입은 슈퍼타입을 행위적으로 대체 가능해야 한다. 만약 Person이 getAge()라는 메시지에 대한 응답으로 나이를 반환한다면 서브타입인 Employee 역시 getAge()라는 메시지에 대한 응답으로 나이를 반환해야 한다.

상속은 코드 중복을 방지하고 공통 코드를 재사용하기 위해 사용된다.

상속은 서브 타이핑(subtyping)서브 클래싱(subclassing)의 두 가지 용도로 사용될 수 있다.

  • 서브 타이핑: 서브 클래스가 슈퍼 클래스를 대체할 수 있는 경우. 설계의 유연성이 목표. 인터페이스 상속(interface inheritance)이라고도 한다. 특정 기대 집합에 대한 서브타입과 슈퍼타입 사이에 구조적, 행위적 순응 관계를 의미하며 대체 가능성을 내포한다.
  • 서브 클래싱: 서브 클래스가 슈퍼 클래스를 대체할 수 없는 경우. 코드의 중복 제거와 재사용이 목표. 구현 상속(implementation inheritance)이라고도 한다.

클래스가 다른 클래스를 상속받았다는 사실만으로 두 클래스 간의 관계가 서브타이핑인지, 서브클래싱인지 알 수 없다. 따라서 이를 확인하려면 클라이언트 관점에서 실제로 어떻게 사용되고 있는지를 확인해야 한다.

여러 클래스로 구성된 상속 계층에서 수신된 메시지를 이해하는 기본적인 방법은 클래스 간의 위임(delegation)을 사용하는 것이다.어떤 객체의 클래스가 수신된 메시지를 이해할 수 없다면 메시지를 부모 클래스에게 위임한다. 부모 클래스에서도 메시지를 이해할 수 없다면 자신의 부모 클래스로 다시 메시지를 위임한다. (메시지 처리할 때까지 반복)

3. 집합과 분해

계층적인 복잡성

안정적인 형태의 부분으로부터 전체를 구축하는 행위를 집합이라고 하고, 전체를 부분으로 분할하는 행위를 분해라고 한다. 집합은 전체의 내부로 불필요한 세부 사항을 감춰주기 때문에 추상화 메커니즘인 동시에 캡슐화 매커니즘이다.

합성 관계

객체와 객체 사이의 전체-부분 관계를 구현하기 위해서는 합성 관계를 사용한다. 합성 관계는 부분을 전체 안에 캡슐화함으로써 인지 과부하를 방지한다. 연관 관계는 그냥 두 객체 사이에 연관이 있다는 것을 말한다.

패키지(모듈)

소프트웨어의 전체적인 구조를 표현하기 위해 관련된 클래스 집합을 하나의 논리적인 단위로 묶는 구성 요소를 패키지 또는 모듈이라고 한다.

장점

  1. 시스템의 전체적인 구조를 이해하기 위해 한 번에 고려해야 하는 요소의 수를 줄일 수 있다.
  2. 개별 클래스가 아닌 클래스의 집합을 캡슐화함으로써 전체적인 복잡도를 낮출 수 있다.

--

--