일단 컴퓨터를 조작하는 것이 추상화를 구축하고, 조작하고, 추론하는 것에 관한 모든 것이라는 것을 깨닫고 나면 (훌륭한) 컴퓨터 프로그램을 작성하기 위한 중요한 전제 조건은 추상화를 정확하게 다루는 능력이라는 것이 명확해진다. - 키스 데블린
지하철 노선도와 추상화
- 초기의 지하철 노선도는 실제와 유사한 물리적인 지형과 역 간 거리를 사실적으로 묘사하고있었다.
- 문제는 이렇게 사실적인 정보가 오히려 지하철을 이용하는 승객들로 하여금 노선도를 이해하기 어렵게 만든다.
- 지형과 축적은 무시하고 역 사이의 연결성에만 집중한 지하철 노선도 등장
- 꼭 알아야 하는 사실만 정확하게 표현하고 몰라도 되는 정보는 무시함
- 이것이 지하철 노선도의 추상화
- 사람들은 본능적으로 이해하기 쉽고 예측 가능한 수준으로 현실을 단순화하는 전략을 따른다.
- 새로운 지하철 노선도는 이용하는 승객들의 목적에 맞게 현실을 단순화했다.
- 새 지하철 노선도가 유용했던 이유는 승객들이 지하철을 바라보는 모델과 일치했기 때문이다.
- 어떤 추상화도 의도된 목적이 아닌 다른 목적으로 사용된다면 오도될 수 있다.
- 추상화의 수준, 이익, 가치는 목적에 의존적이다.
추상화
- 어떤 양상, 세부 사항, 구조를 좀 더 명확하게 이해하기 위해 특정 절차나 물체를 의도적으로 생략하거나 감춤으로써 복잡도를 극복하는 방법.
복잡성을 다루기 위해 추상화는 두 차원에서 이뤄진다.
- 첫 번째 차원: 구체적인 사물들 간의 공통점은 취하고 차이점은 버리는 일반화를 통해 단순화
- 두 번째 차원: 중요한 부분을 강조하기 위해 불필요한 세부 사항 제거함으로써 단순화
- 객체지향 패러다임은 객체라는 추상화를 통해 현실의 복잡성을 극복한다.
- 공통점을 기반으로 객체들을 묶기 위한 그릇을 개념(concept)이라고 한다.
- 개념을 이용하면 객체를 여러 그룹으로 분류(classification)할 수 있다.
- 결국 각 객체는 특정한 개념을 표현하는 그룹의 일원으로 포함된다.
- 객체란 특정한 개념을 적용할 수 있는 구체적인 사물을 의미한다. 개념이 객체에 적용됐을 때 객체를 개념의 인스턴스라고 한다.
일반적으로 객체의 분류 장치로서 개념을 이야기 할 때는 아래의 세 가지 관점을 함께 언급한다.
1 . 심볼(symbol): 개념을 가리키는 간략한 이름이나 명칭
- 트럼프
- 내연(intension): 개념의 완전한 정의를 나타내며 내연의 의미를 이용해 객체가 개념에 속하는지 여부를 확인할 수 있다.
- 몸이 납작하고 두 손과 두 발은 네모 귀퉁이에 달려 있는 등장인물
- 외연(extension): 개념에 속하는 모든 객체의 집합(set)
- 정원사, 병사, 신하, 왕자와 공주, 하객으로 참석한 왕과 완비들, 하트 잭, 하트 왕과 하트 여왕
- 개념이 심볼, 내연, 외연으로 구성돼 있다는 사실보다는 개념을 이용해 객체를 분류할 수 있다는 사실이 더 중요하다.
- 개념을 이용해 공통점을 가진 객체를 분류할 수 있다는 아이디어는 객체지향 패러다임이 복잡성을 극복하는 데 사용하는 가장 기본적인 인지 수단이기 때문이다.
- 분류란 객체에 특정한 개념을 적용하는 작업이다. 객체에 특정한 개념을 적용하기로 결심했을 때 우리는 그 객체를 특정한 집합의 멤버로 분류하고 있는 것이다.
- 분류는 객체지향의 가장 중요한 개념 중 하나다.
- 어떤 객체를 어떤 개념으로 분류할지가 객체지향의 품질을 결정한다.
- 더 중요한 것은 적절한 분류 체계는 애플리케이션을 다루는 개발자의 머릿속에 객체를 쉽게 찾고 조작할 수 있는 정신적인 지도를 제공한다는 것이다.
- 앞에서 추상화가 두 가지 차원에서 이뤄진다고 했던 것을 떠올려 보라.
- 개념을 통해 객체를 분류하는 과정은 추상화의 두 가지 차원을 모두 사용한다.
- 타입의 정의는 개념의 정의와 완전히 동일하다.
- 안타깝게도 타입이 근본적으로 개념과 동일하다고 하더라도 컴퓨터 내부로 들어오는 순간 좀 더 기계적인 의미로 윤색될 수밖에 없다.
- 컴퓨터 안의 bit들을 목적에 따라 분류하면서 타입 시스템이 자라났다.
- 타입 시스템의 목적은 데이터가 잘못 사용되지 않도록 제약사항을 부과하는 것이다.
- 중요한 두 가지 사실
- 타입은 데이터가 어떻게 사용되느냐에 관한 것이다.
- 일반적으로 데이터를 이용해 수행할 수 있는 작업을 연산자(operator)라고 한다.
- 어떤 데이터에 어떤 연산자를 적용할 수 있는지가 그 데이터의 타입을 결정한다.
- 타입에 속한 데이터를 메모리에 어떻게 표현하는지는 외부로부터 철저하게 감춰진다.
- 타입은 데이터가 어떻게 사용되느냐에 관한 것이다.
- 데이터 타입은 메모리 안에 저장된 데이터의 종류를 분류하는 데 사용하는 메모리 집합에 관한 메타데이터다. 데이터에 대한 분류는 암시적으로 어떤 종류의 연산이 해당 데이터에 대해 수행될 수 있는지를 결정한다.
- 객체지향 프로그램을 작성할 때 우리는 객체를 일종의 데이터처럼 사용한다.
- 객체를 타입에 따라 분류하고 그 타입에 이름을 붙이는 것은 결국 프로그램에서 사용할 새로운 데이터 타입을 선언하는 것과 같다.
- 데이터 타입에 관한 두 가지 조언은 객체의 타입을 이야기할 때도 동일하게 적용된다.
- 어떤 객체가 어떤 타입에 속하는지를 결정하는 것은 객체가 수행하는 행동이다. 어떤 객체들이 동일한 행동을 수행할 수 있다면 그 객체들은 동일한 타입으로 분류될 수 있다.
- 객체의 내부적인 표현은 외부로부터 철저하게 감춰진다. 객체의 행동을 가장 효과적으로 수행할 수만 있다면 객체 내부의 상태를 어떤 방식으로 표현하더라도 무방하다.
- 두 가지 조언으로부터 객체지향 설계에 대한 중요한 원칙을 이끌어낼 수 있다.
- 어떤 객체를 다른 객체와 동일한 타입으로 분류하는 기준은?
- 그 객체가 타입에 속한 다른 객체와 동일한 행동을 하는지 O
- 그 객체가 어떤 데이터를 가지고 있는지는 X
- 객체의 타입을 결정하는 것은 객체의 행동뿐이다.
- 동일한 행동은 동일한 책임을 의미하며, 동일한 책임이란 동일한 메시지 수신을 의미한다.
- 내부 표현 방식이 다르더라도 동일한 타입에 속한 객체는 동일한 메시지를 수신하고 처리할 수 있다 → 다형성
- 훌륭한 객체지향 설계는 외부에 행동만을 제공하고 데이터는 행동 뒤로 감춰야 한다 → 캡슐화
- 책임 주도 설계(Responsibility-Driven Design)
- 트럼프 인간과 트럼프를 살펴보자.
- 트럼프 인간은 트럼프의 일종이지만 일반적인 트럼프 카드보다 좀 더 특화된 행동을 하는 트럼프다.
- 외연이라는 객체 집합의 관점에서 트럼프는 트럼프 인간을 포괄하는 좀 더 일반적인 개념이다.
- 이 두 개념 사이의 관계를 일반화/특수화 관계라고 한다.
- 트럼프는 트럼프 인간보다 더 일반적인 개념이다.
- 일반화/특수화는 행동에 관한 것이다.
- 특수한 타입은 일반적인 타입이 할 수 있는 모든 행동을 동일하게 수행 가능해야 한다.
-
좀 더 일반적인 타입을 슈퍼타입(Supertype)이라고 하고 좀 더 특수한 타입을 서브타입(Subtype)이라고한다.
-
슈퍼타입과 서브타입에서 중요한 것은 두 타입 관의 관계가 행동에 의해 결정된다는 점이다.
-
즉, 어떤 타입이 다른 타입의 서브타입이 되기 위해서는 행위적 호환성을 만족시켜야 한다.
- 서브타입은 슈퍼타입을 대체할 수 있어야 한다.
-
일반화/특수화 관계를 표기하는 방법 (슈퍼타입 상단, 서브타입 하단)
-
슈퍼타입의 행동은 서브타입에게 자동으로 상속된다.
- 서브타입은 슈퍼타입의 행위에 추가적으로 특수한 자신만의 행동을 추가하는 것이므로
-
일반화는 추상화를 위한 도구다.
- 앨리스가 어떻게 변할 수 있는지 그 다양한 가능성을 고려할 때는 구체적으로 키가 얼마인가보다는 단순히 키가 변할 수 있다는 가능성에 집중하는 것이 더 간단하다.
- 결국 키는 버섯을 먹거나, 음료를 마시거나, 부채질를 할 때마다 변할 것이다.
- 실제로 그런 행동을 할 때 키가 어떤 값인지는 중요하지 않다.
- 타입은 추상화다.
- 결국 타입은 시간에 따른 객체의 상태 변경이라는 복잡성을 단순화할 수 있는 효과적인 방법이다.
- 우리는 두 가지 모델을 동시에 고려한다.
- 동적 모델
- 객체의 스냅샷: 객체가 특정 시점에 구체적으로 어떤 상태를 가지는지
- 객체 상태변경 디버깅
- 정적 모델
- 타입 모델: 객체가 가질 수 있는 모든 상태와 행동을 시간에 독립적으로 표현
- 클래스 작성하는 시점
- 동적 모델
- 객체지향 애플리케이션을 설계하고 구현하기 위해서는 객체 관점의 동적 모델과 객체를 추상화한 타입 관점의 정적 모델을 적절히 혼용해야 한다.
- 타입을 구현하는 가장 보편적인 방법은 클래스를 이용하는 것이다.
- 클래스와 타입은 동일한 것이 아니다.
- 클래스는 단지 타입을 구현할 수 있는 여러 구현 매커니즘 중 하나일 뿐이다.
- 객체를 분류하는 기준은 타입이며, 타입을 나누는 기준은 객체가 수행하는 행동이다.