추상화 기법
추상화는 도메인의 복잡성을 단순화하고 직관적인 멘탈 모델을 만드는 데 사용할 수 있는 가장 기본적인 인지 수단이다. 사람들은 개념을 구조화하고 단순화하기 위해 다양한 추상화 기법을 사용한다.
다음은 중요한 추상화 기법의 종류를 나타낸 것이다. 각 추상화 기법은 복잡성을 낮추기 위해 사물의 특정한 측면을 감춘다.

- 분류와 인스턴스화: 분류는 객체들의 공통적인 특성을 기준으로 범주를 묶는 과정이고, 인스턴스화는 그 범주로부터 구체적인 객체를 만들어내는 과정이다.
- 일반화와 특수화: 일반화는 여러 범주의 공통점을 추려 상위 개념으로 묶는 것이고, 특수화는 그 개념을 더 구체적으로 나누는 과정이다.
- 집합과 분해: 집합은 여러 부분을 모아 하나의 전체로 보는 것이고, 분해는 전체를 구성 요소로 나누는 과정이다.
객체지향의 가장 큰 장점은 동일한 추상화 기법을 프로그램의 분석, 설계, 수현 단계에 걸쳐 일관성 있게 적용할 수 있다는 점이다.
분류와 인스턴스화
개념과 범주
객체를 분류하고 범주로 묶는 것은 객체들의 특정 집합에 공통의 개념을 적용하는 것을 의미한다.
💡 개념: 속성과 행위가 유사한 객체에 공통적으로 적용되는 관념이나 아이디어
- 객체지향의 세계에서 개념을 가리키는 표준 용어는 타입이다.
💡 분류: 세상에 존재하는 객체에 개념을 적용하는 과정
- 객체를 특정한 개념을 나타내는 집합의 구성 요소로 포함시킨다.
사람들은 분류를 통해 개별 현상을 하나의 개념으로 다룬다. 이때 '수많은 개별적인 현상들'을 객체라고 하고, '하나의 개념'을 타입이라고 한다.
분류는 객체와 타입 간의 관계를 나타낸 것이다. 어떤 객체가 타입의 정의에 부합할 경우 그 객체는 해당 타입으로 분류되며 자동으로 타입의 인스턴스가 된다.
타입
타입을 객체의 분류 장치로 적용할 수 있으려면 다음과 같은 세 가지 관점에서의 정의가 필요하다.
- 심볼: 타입을 가리키는 간략한 이름이나 명칭
- 내연: 타입의 완전한 정의. 내연의 의미를 이용해 객체가 타입에 속하는지 여부를 확인할 수 있다.
- 외연: 타입에 속하는 모든 객체들의 집합
아래 그림은 객체를 자동차라는 타입으로 분류하는 데 필요한 정의를 심볼, 내연, 외연 측면으로 나타낸 것이다.

이처럼 도메인을 분석하는 동안 이름과 의미, 객체들의 집합을 이용해 개념을 정의할 수 있다.
외연과 집합
타입의 외연은 해당 타입에 속하는 객체들의 집합을 의미한다. 즉, 집합은 외연을 나타내는 또 다른 명칭이다. 또한 하나의 객체는 동시에 여러 집합에 포함될 수 있다.

- 단일 분류: 하나의 객체가 한 시점에 하나의 타입에만 속하는 것
- 다중 분류: 하나의 객체가 한 시점에 여러 타입에 속하는 것
대부분의 객체지향 프로그래밍 언어는 단일 분류만 지원한다. 즉, 하나의 객체는 하나의 클래스 인스턴스만 될 수 있으며, 동시에 여러 클래스의 인스턴스가 될 수는 없다.
이때 다중 분류를 다중 상속과 혼동해서는 안 된다. 다중 상속은 하나의 타입이 여러 슈퍼타입을 가질 수 있게 하는 것이고, 다중 분류는 하나의 객체가 여러 타입에 동시에 속할 수 있게 하는 개념이다.
객체는 상황에 따라 자신이 속한 타입을 변경할 수도 있다.
- 동적 분류: 객체가 자신이 속하는 타입을 변경할 수 있는 경우
- 정적 분류: 객체가 자신의 타입을 변경할 수 없는 경우
다중 분류와 동적 분류는 현실 세계의 복잡성을 표현하는 데 유용하지만, 대부분의 객체지향 언어는 객체의 타입 변경을 지원하지 않는다. 따라서 실제 구현에서는 주로 단일 분류와 정적 분류를 사용하며, 특별한 유연성이 필요한 경우에만 다중 분류와 동적 분류를 적용하는 것이 일반적이다.
클래스
객체지향 프로그래밍 언어를 이용해 타입을 구현하는 가장 일반적인 방법은 클래스를 이용하는 것이다. 다만 클래스와 타입은 동일한 개념은 아니다. 클래스는 타입을 구현할 뿐만 아니라 코드 재사용의 용도로도 사용된다. 또한 타입은 클래스 외에도 추상 클래스나 인터페이스로 구현할 수 있다.
객체들의 카테고리는 객체들이 공유하는 공통적인 특성에 의해 정의된다. 클래스 기반 객체지향 언어는 이러한 공통된 본질적 속성을 기준으로 타입을 정의하며, 같은 클래스의 인스턴스들은 동일한 속성과 특성을 공유한다.
반면 자바스크립트처럼 클래스가 존재하지 않는 프로토타입 기반의 언어는 객체를 복사하고 확장하는 방식으로 동작한다.
일반화와 특수화
범주의 계층
린넨의 생물 분류 체계는 범주 간의 계층 구조를 가진다. 좀 더 세부적인 범주가 계층의 하위에 위치하고 좀 더 일반적인 범주가 계층의 상위에 위치한다.
💡 일반화: 계층의 상위 범주가 하위 범주의 공통적인 특성을 추상화한 것
💡 특수화: 계층의 하위 범주가 상위 범주의 특성을 구체화한 것
서브타입
객체지향의 세계에서 범주는 개념을 의미하고, 개념은 타입을 의미하므로 일반화와 특수화는 계층 구조 안에 존재하는 타입 간의 관계를 의미한다. 따라서 더 일반적인 타입을 이용해 좀 더 세부적인 타입을 정의함으로써 타입 간의 계층 구조를 구축할 수 있다.
- 슈퍼타입: 더 일반적인 타입
- 서브타입: 더 특수한 타입
일반화와 특수화의 계층 구조에서 서브타입은 슈퍼타입이 가진 본질적인 속성과 함께 자신만의 추가적인 속성을 가진다.

내연의 관점에서 특수한 타입은 일반적인 타입의 속성을 포함한다.

외연의 관점에서 서브타입은 슈퍼타입의 부분집합이다.
크레이그 라만은 어떤 타입이 다른 타입의 서브타입이 되기 위해서는 '100% 규칙'과 'Is-a 규칙'을 준수해야 한다고 말한다.
- 100% 규칙: 슈퍼타입의 정의가 100% 서브타입에 적용돼야만 한다. 서브타입은 속성과 연관관계 면에서 슈퍼타입과 100% 일치해야 한다.
- ls-a 규칙: 서브타입의 모든 인스턴스는 슈퍼타입 집합에 포함돼야 한다.
상속
일반화와 특수화 관계를 구현하는 가장 일반적인 방법은 클래스 간의 상속을 사용하는 것이다. 하지만 모든 상속 관계가 일반화 관계인 것은 아니다. 두 클래스 사이에 상속 관계가 존재할 때 이 관계를 반드시 일반화 관계라고 할 수는 없다.
일반화의 원칙은 서브타입이 슈퍼타입에 순응(conformance)해야 한다는 점이다. 순응에는 구조적 순응과 행위적 순응이 있다.
- 구조적 순응
- 서브타입이 슈퍼타입의 속성과 연관관계를 그대로 가져야 한다는 의미다. 즉, 구조적으로 동일한 기대를 만족해야 한다.
- 예를 들어 `Person`이 `name` 속성을 가진다면, 서브타입인 `Employee`도 `name` 속성을 가져야 한다.
- 행위적 순응
- 서브타입이 슈퍼타입과 동일한 방이식으로 동작해야 한다는 의미다.
- 이를 리스코프 치환 원칙(LSP)이라고도 한다.
- 예를 들어 `Person`이 `getAge()` 메시지에 나이를 반환한다면, `Employee` 역시 같은 메시지에 대해 나이를 반환해야 한다.
상속은 크게 서브타이핑과 서브클래싱의 두 가지 용도로 사용된다.
- 서브타이핑
- 서브 클래스가 슈퍼 클래스를 대체할 수 있는 경우
- 목적은 설계의 유연성이며, 인터페이스 상속이라고도 한다.
- 서브클래싱
- 서브 클래스가 슈퍼 클래스를 대체할 수 없는 경우
- 목적은 코드의 중복 제거와 재사용이며, 구현 상속이라고 한다.
따라서 모든 상속이 일반화 관계인 것은 아니다. 중요한 기준은 서브클래스가 슈퍼클래스를 실제로 대체할 수 있는지 여부다.
또한 객체지향 언어는 위임을 통해 메시지를 처리한다. 클래스 기반 언어는 부모 클래스에, 프로토타입 기반 언어는 부모 객체에 메시지를 위임한다.
집합과 분해
계층적인 복잡성
- 복잡성은 '계층'의 형태를 띤다.
- 단순한 형태로부터 복잡한 형태로 진화하는데 걸리는 시간은 그 사이에 존재하는 '안정적인 형태'의 수와 분포에 의존한다.
💡 집합: 안정적인 형태의 부분으로부터 전체를 구축하는 행위
- 여러 요소를 하나의 단위로 다뤄 복잡성을 줄이고 세부사항을 추상화한다.
- 전체 내부를 감춤으로써 외부에 영향을 주지 않는 캡슐화 역할을 수행한다.
💡 분해: 전체를 부분으로 분할하는 행위
- 필요한 시점에 부분을 새로운 전체로 다룰 수 있게 한다.
- 전체와 부분 간의 일관된 계층 구조는 재귀적인 설계를 가능하게 한다.
- 집합과 분해는 한 번에 다뤄야 하는 요소의 수를 감소시킴으로써 인지 과부하를 방지한다.
합성 관계
주문 항목은 반드시 특정 주문에 포함되며 독립적으로 존재할 수 없다. 이처럼 객체와 객체 사이의 전체-부분 관계를 표현하는 것을 합성 관계라고 한다.

합성 관계는 부분을 전체 안에 캡슐화함으로써 인지 과부하를 방지한다. 주문 항목은 주문의 일부이기 때문에, 필요할 때만 내부 세부 사항을 확인하고 평소에는 주문 자체를 하나의 단위처럼 다룰 수 있다.

반면 주목 항목과 상품은 단순히 연결만 되어 있는 관계이며, 이를 연관관계라고 한다.
합성 관계는 생명주기를 공유한다. 따라서 주문이 삭제되면 주문 항목도 삭제되지만, 상품은 독립적으로 존재할 수 있다.
패키지
합성 관계를 이용해 커다란 객체 그룹을 단순화하더라도 클래스의 수가 많아지면 클래스 간의 의존성을 관리하기 어려워진다. 따라서 소프트웨어 구조를 한눈에 이해할 수 있는 큰 그림이 필요하다.
이를 위해 관련된 클래스들을 하나의 논리적인 단위로 묶는데, 이를 패키지 또는 모듈이라고 한다. 패키지는 여러 클래스를 하나로 캡슐화해 복잡성을 줄이고 시스템 구조를 더 쉽게 이해할 수 있게 한다.
합성 관계가 내부 객체를 감춰 구조를 단순화한듯, 패키지는 내부 클래스를 감춤으로써 시스템 전체 구조를 추상화한다.

'책' 카테고리의 다른 글
| [객체지향의 사실과 오해] 7장 함께 모으기 (0) | 2026.05.06 |
|---|---|
| [객체지향의 사실과 오해] 6장 객체 지도 (0) | 2026.05.04 |
| [객체지향의 사실과 오해] 5장 책임과 메시지 (0) | 2026.05.01 |
| [객체지향의 사실과 오해] 4장 역할, 책임, 협력 (1) | 2026.04.13 |
| [객체지향의 사실과 오해] 3장 타입과 추상화 (1) | 2026.01.16 |