본문 바로가기

Study

객체지향의 사실과 오해 부록A 발표 자료

목차

  • 부록A 추상화 기법
    • 분류와 인스턴스화
      • 개념과 범주
      • 타입
      • 외연과 집합
      • 클래스
    • 일반화와 특수화
      • 범주의 계층
      • 서브타입
      • 상속
    • 집합과 분해
      • 계층적인 복잡성
      • 합성 관계
      • 패키지

부록A 추상화 기법

추상화 기법

  • 추상화를 통해 복잡한 도메인을 단순하고 직관적으로 만들 수 있다.
  • 추상화 기법을 통해 같은 특성을 가진 객체들을 동일한 타입으로 분류할 수 있다.
    • 분류를 통해 각 객체의 세부 사항을 숨기고, 공통 특성을 통해 범주를 형성한다. 이를 반대로 수행해 객체를 인스턴스화할 수 있다.
      • 예) 소나타, 그렌저, 제네시스 —> 자동차 —> 소나타, 그렌저, 제네시스
    • 객체 간 차이를 숨기고 공통 특성을 추출하여 객체를 일반화한다. 이를 반대로 수행해 객체를 특수화할 수 있다.
      • 예) 자동차, 자전거 —> 운송수단 —> 자동차, 자전거
    • 객체의 부분에 관한 세부사항을 숨기고, 부분을 바탕으로 전체를 형성해 집합을 만든다. 이를 반대로 수행해 객체를 분해할 수 있다.
      • 예) 섀시, 차체, 엔진 —> 자동차 —> 섀시, 차체, 엔진

분류와 인스턴스화

개념과 범주

  • 객체를 분류하고 범주화하는 것은 특정 집합에 공통 개념을 적용하는 것이다.
    • 개념은 유사한 속성, 행위를 가진 객체에 적용되는 관념 또는 아이디어다.
      • 예) 나무: 잎과 줄기를 가진 다년생 식물(유사 속성)
      • 예) 자동차: 운송수단(유사 행위)
    • 분류는 객체에 개념을 적용하는 과정이다. 분류의 반대과정은 인스턴스화다.
      • ‘객체’는 ‘개별적인 현상’이고, 객체들을 범주화한 ‘개념’은 ‘타입’이다.
  • 분류와 범주화는 인간이 실세계를 인식하는 형태를 반영한 것이다.
    • 이러한 과정을 통해 세상의 복잡성을 낮출 수 있다.

타입

  • 어떤 객체가 해당 타입에 속하는지 결정하려면 먼저 대상 타입에 대한 명확한 정의를 내려야 한다.
    • 정의 방법은 심볼, 내연, 외연의 관점으로 나뉜다.
      • 심볼은 타입의 이름이다. 타입에 대해 이해하고 의사소통할 수 있는 수단이다.
        • 예) 자동차
      • 내연은 타입의 완전한 정의이다. 어떤 객체가 해당 타입에 속하는지를 결정하는 기준이다.
        • 예) 원동기를 동력원으로 주행하는, 사람이나 화물을 운반하는 기계
      • 외연은 해당 타입에 속하는 모든 객체의 집합이다. 내연에 부합하는 객체를 외연에 포함시킨다.
        • 예) 소나타, 그렌저, 제네시스 등

외연과 집합

  • 집합은 외연과 같은 말이며, 한 객체는 여러 집합에 속할 수 있다.
    • 예) 사무용 컴퓨터 집합에 속하는 객체는 데스크톱 컴퓨터 집합 또는 노트북 컴퓨터 집합에도 속할 수 있다.
    • 이는 동일한 객체를 다양한 방식으로 인지하는 인간의 일반적인 방식이다.
  • 한 객체가 하나의 타입에 속하는 것을 단일 분류(single classification), 여러 타입에 속하는 것을 다중 분류(multiple classification)라고 한다.
    • 다중 분류는 다중 상속과 다르다. 다중 분류는 부모 타입을 정의하지 않아도 서로 다른 타입의 인스턴스가 될 수 있는 것이다.
  • 대부분의 프로그래밍 언어에서 단일 분류만을 지원하기 때문에, 모든 객체는 한 클래스의 인스턴스여야만 한다.
  • 객체가 타입을 변경할 수 있는 것을 동적 분류(dynamic classification), 변경이 불가능한 것을 정적 분류(static classification)라고 한다. 마찬가지로 대부분의 프로그래밍 언어에서 정적 분류만을 지원한다.
  • 다중 분류와 동적 분류를 함께 적용하면 실세계의 복잡성을 다루기 용이해지지만, 프로그래밍 언어로 옮기기에는 제약이 따른다.
    • 따라서 먼저 다중 분류와 동적 분류를 활용해 도메인 모델의 초안을 설계하고, 실제 구현에 적합한 단일 분류와 정적 분류 방식으로 재조정하는 방식이 바람직하다.
  • 디자인 템플릿을 이용하면 다중 분류와 동적 분류를 구현할 수 있지만, 반드시 필요한 상황에서만 사용하는 것이 추천된다.

클래스

  • 클래스는 타입을 구현하고 코드를 재사용한다.
    • 추상 클래스나 인터페이스를 이용해도 타입을 구현할 수 있다.
  • 객체지향은 아리스토텔레스의 분류법에 따라 객체들의 공통적인 특성을 기준으로 객체를 분류한다.
  • 객체의 핵심적인 속성은 본질적 속성이고, 그 외의 속성은 우연적 속성이다.
    • 대부분의 객체지향 언어는 본질적 속성만을 표현하기 때문에, 모든 객체가 동일한 속성을 가진다.
  • 클래스가 없는 프로토타입 언어에서는 본질적 속성으로 분류하지 않고, 프토로타입을 통해 인스턴스화한다.

일반화와 특수화

범주의 계층

  • 카를로스 린네는 자연에 존재하는 생물을 보편적 분류 체계인 계, 문, 강, 목, 과, 속, 종과 표준 명칭을 정의하는 이명법으로 분류했다.
    • 이는 해당 생물에 대해 알지 못하더라도, 같은 범주에 속하는 생물을 통해 해당 생물을 유추할 수 있게 해 준다.
      • 예) 얼룩 고양이: 동물계 척색동물문 포유류강 육식동물목 고양이과 고양이속 고양이종 —> 얼룩고양이를 본 적이 없더라도, 포유류와 육식동물의 특성을 통해 고양이의 특성을 유추할 수 있다.
    • 상위 범주를 하위 범주의 일반화, 하위 범주를 상위 범주의 특수화라고 한다.

서브타입

  • 객체지향에서 일반적 타입은 슈퍼타입, 특수한 타입은 서브타입이라고 한다.
    • 자연에서와 마찬가지로 서브타입은 슈퍼타입의 본질적 속성에 다른 속성을 추가(extends)한 것이다.
      • 생물처럼 귀납적 추리를 통해 같은 범주에 속한 객체를 유추할 수 있다.
      • 부분적인 사실을 통해 복잡한 사실을 추론할 수 있게 된다.
    • 외연의 관점에서 슈퍼타입이 더 넓은 범위를 포괄하기 때문에, 서브타입은 슈터타입의 부분집합에 속한다.
    • 서브타입의 분류는 ‘100% 규칙’(내연 관련)과 ‘Is a’(외연 관련) 규칙을 따른다.
      • 100% 규칙: 슈퍼타입의 정의를 정확히 따른다.
        • 예) 육식동물은 고기를 먹는다. —> 고양이는 고기를 먹는다.
      • Is-a 규칙: 서브타입의 모든 인스턴스는 슈퍼타입 집합에 포함된다(subtype is a supertype).
        • 예) 고양이는 육식동물이다 (O), 육식동물은 고양이다(X)

상속

  • 상속은 일반화와 특수화 관계를 표현하는 가장 일반적인 방법이지만, 모든 상속 관계가 해당하는 것은 아니다.
  • 어떤 타입의 서브타입이 되려면 해당 타입에 순응해야 하며, 순응은 구조적인 순응과 행위적인 순응으로 나뉜다.
    • 구조적인 순응은 내연과 관련된 것으로서, 서브타입은 슈퍼타입의 속성과 연관관계 측면에서 일치해야 한다.
      • 예) Person이 name 속성을 가지면 서브타입인 Employee도 name 속성을 가진다.
    • 행위적인 순응은 행위와 관련된 것으로서, 리스코프 치환 원칙(객체지향 설계 원칙인 SOLID 원칙의 L)이라고도 한다. 서브타입은 행위적으로 슈퍼타입을 대체 가능해야 한다.
      • 예) Person의 getAge() 메소드가 나이를 반환하는 메소드라면, 서브타입인 Employee의 getAge() 메소드도 같은 행위를 해야 한다. 따라서 Employee는 Person을 행위적으로 대체할 수 있다.
      • 서브타입은 슈퍼타입의 행위를 다른 방식으로 수정, 확장(Overriding)할 수 있으므로, 프로그래밍 언어에서 대체 가능성은 보장되지 않는다.
  • 상속을 통해 코드 중복을 방지하고, 코드를 재사용할 수 있다.
  • 상속의 용도는 서브타이핑(인터페이스 상속)과 서브클래싱(구현 상속)으로 나뉜다.
    • 서브타이핑은 서브클래스가 슈퍼클래스를 대체할 수 있는 것이고, 서브클래싱은 대체할 수 없는 것이다.
    • 서브타이핑은 설계의 유연성을 추구하고, 서브클래싱은 코드의 중복 제거와 재사용을 추구한다.
  • 다른 객체로부터의 메시지를 이해할 수 없다면, 해당 메시지를 부모 클래스가 이해할 수 있거나 최상위 부모 클래스에 위임될 때까지 부모 객체에 위임하는 작업을 반복한다.
    • 클래스가 없는 프로토타입 언어에서는 객체 간 관계를 통해 연결한다. 마찬가지로 이해할 수 없는 메시지를 부모 객체로 위임하는 작업을 반복한다.

집합과 분해

계층적인 복잡성

  • 시계 제작자인 템프스는 1,000개의 시계 부품을 조립하다 고객의 전화가 오면 통화 후 다시 조립했다. 다시 조립해야 하는 부품의 개수가 많았다.
  • 다른 시계 제작자인 호라는 10개의 부품으로 10개, 다시 그 10개로 10개를 조립했다. 고객의 전화가 오더라도 다시 조립해야 하는 부품의 개수가 적었다.
    • 단순한 형태로부터 복잡한 형태를 만들 때, 중간 계층에 안정적인 형태를 확보함으로써 작업 시간을 단축할 수 있다.
  • 부분으로부터 전체를 구성하는 것을 집합, 전체를 부분으로 나누는 것을 분해라고 한다.
    • 집합은 불필요한 세부 사항을 배제(추상화)함으로써 복잡성을 줄일 수 있다. 이를 분해하면 다시 작은 전체 구조로 분할된다. 이는 재귀 설계를 달성할 수 있게 해 준다.
      • 재귀 설계에서 외부는 내부의 구조를 알지 못하고, 내부의 구성 변경은 외부에 영향을 미치지 않는다(캡슐화). 따라서 동시에 다뤄야 하는 요소를 줄여 준다.
    • 인간은 본능적으로 세계를 내부와 외부로 구분하기 때문에 인위적인 경계를 쉽게 나누고(그릇 은유), 집합 구조를 수월하게 다룰 수 있다.
      • 그릇 은유는 인간이 영토를 소유하려는 본능에서 비롯된다.

합성 관계

  • 객체 간 전체-부분 관계의 구현을 합성 관계라고 한다. 합성 관계에 있는 객체들은 생명 주기를 공유한다(Cascade, 영속성 전이).
    • 예) 여러 상품을 주문하면 상품의 주문 항목들은 주문 집합으로 합쳐지고, 주문과 주문 항목은 독립적으로 존재할 수 없다. 따라서 합성 관계를 맺고 있다.
  • 합성 관계는 주문 항목의 캡슐화를 통해 주문과 상품만을 다룰 수 있게 해 준다. 이는 인간이 동시에 다뤄야 하는 세부사항을 배제함으로써 복잡성을 줄이고 인지 과부하를 방지한다.
  • 전체-부분 관계가 아니지만 서로 관계를 맺고 있는 것을 연관 관계라고 한다. 각자 독립적으로 존재하므로, 생명 주기를 공유하지 않는다. 따라서 합성 관계에 비해 결합도가 낮다.
    • 예) 상품은 주문 항목과 전체-부분으로 나뉘지 않는다. 둘은 독립적으로 존재한다. 따라서 연관 관계를 맺고 있다.

패키지

  • 패키지(모듈)는 높이와 축척을 통해 전체적인 구조를 쉽게 파악할 수 있게 해 주는 지도와 역할을 한다.
  • 서로 관련 있는 클래스 집합을 논리 단위인 패키지로 통합함으로써, 물리적 형태가 존재하지 않는 소프트웨어의 전체적인 구조를 쉽게 이해할 수 있다.
    • 동시에 고려해야 하는 요소를 줄인다.
    • 캡슐화를 통해 소프트웨어의 복잡도를 낮춘다.
    • 서로 연관된 코드에 대한 이해도가 상승한다.
  • 합성 관계와 유사한 개념이지만, 합성 관계는 객체, 패키지는 클래스에 적용된다.