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

yeonk·2023년 1월 10일
0

OOP

목록 보기
7/7
post-thumbnail

추상화 기법


추상화는 도메인의 복잡성을 단순화하고 직관적인 멘탈 모델을 만드는 데 사용할 수 있는 가장 기본적인 인지 수단이다.

객체지향의 가장 큰 장점은 동일한 추상화 기법을 프로그램의 분석, 설계, 구현 단계에 걸쳐 일관성 있게 적용할 수 있다는 점이다.

각 추상화 기법은 복잡성을 낮추기 위해 사물의 특정한 측면을 감춘다.










추상화 기법의 종류

  • 분류와 인스턴스화

    • 분류: 객체의 구체적인 세부 사항을 숨기고 인스턴스 간에 공유하는 공통적인 특성을 기반으로 범주를 형성하는 과정

    • 인스턴스화: 분류의 역. 범주로부터 객체를 생성하는 과정

  • 일반화와 특수화

    • 일반화: 범주 사이의 차이를 숨기고 범주 간에 공유하는 공통적인 특성을 강조한다.

    • 특수화: 일반화의 역

  • 집합과 분해

    • 집합: 부분과 관련된 세부 사항을 숨기고 부분을 사용해서 전체를 형성하는 과정

    • 분해: 집합의 반대 과정. 전체를 부분으로 분리하는 과정










분류와 인스턴스화


개념과 범주

객체를 분류하고 범주로 묶는 것은 객체들의 특정 집합에 공통의 개념을 적용하는 것을 의미

  • 분류는 객체를 특정한 개념을 나타내는 집합의 구성 요소로 포함시킨다.

  • 분류를 통해 개별 현상(객체)을 하나의 개념(타입)으로 다룬다. 즉, 분류는 객체를 타입과 연관시키는 것이다.

  • 타입은 속성과 행위가 유사한 객체에 공통적으로 적용되는 관념이나 아이디어를 의미한다.

  • 어떤 객체가 타입의 정의에 부합할 경우 그 객체는 해당 타입으로 분류되며 자동으로 타입의 인스턴스가 된다.










타입

객체를 타입에 따라 분류하기 위해서는 객체가 타입에 속하는지 여부를 확인할 수 있어야 한다.

분류 장치로서의 타입 적용을 위해 세 가지 관점에서의 정의가 필요

  • 심볼: 타입을 가리키는 간략한 이름이나 명칭

  • 내연: 타입의 완전한 정의, 내연의 의미를 이용해 객체가 타입에 속하는지 여부를 확인할 수 있다.

  • 외연: 타입에 속하는 모든 객체들의 집합

심볼은 내연과 외연에 모호하지 않은 이름을 붙임으로써 타입을 쉽게 참조하고 커뮤니케이션할 수 있게 한다.










외연과 집합

타입의 외연은 타입에 속하는 객체들의 집합으로 표현한다.
집합은 외연을 가리키는 또 다른 명칭이다.










단일 분류와 다중 분류

대부분의 객체지향 프로그래밍 언어들은 단일 분류만을 지원한다.
다중 분류를 다중 상속과 혼동하지 않도록 주의한다.

  • 단일 분류(single classification) : 한 객체가 한 시점에 하나의 타입에만 속하는 것

  • 다중 분류(multiple classification): 한 객체가 한 시점에 여러 타입에 속하는 것










동적 분류와 정적 분류

다중 분류와 동적 분류는 서로 배타적인 개념이 아니다.
개념적인 관점에서 다중 분류와 동적 분류를 함께 적용하는 것이 실세계의 복잡성을 모델링하는 데 유용하다.

우리가 사용하는 대부분의 언어는 정적 분류만 허용하며 동적 분류를 구현할 수 있는 방법을 제공하지 않는다.

  • 동적 분류(dynamic classification): 객체가 한 집합에서 다른 집합의 원소로 자신이 속하는 타입을 변경할 수 있는 경우

  • 정적 분류(static classification): 객체가 자신의 타입을 변경할 수 없는 경우










클래스

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

  • 만약 객체들이 동일한 특성을 가진다면 그것들은 동일한 카테고리에 속하며, 객체들의 카테고리는 객체들이 공유하는 공통적인 특성에 의해 정의된다.

  • 아리스토텔레스는 객체의 특성을 본질적인 속성과 우연적인 속성으로 분류했다.

    • 본질(essence) 이란 한 사물의 가장 핵심적이고 필수불가결한 속성이다.
    • 우연적(accidental) 속성: 본질적이지 않은 속성
  • 클래스는 객체가 공유하는 본질적인 속성을 정의한다.



대부분의 객체지향 언어는 본질적인 속성은 표현할 수 있지만 우연적인 속성은 표현할 수 없다.
따라서 동일한 범주에 속하는 객체는 모두 동일한 속성을 가져야만 한다.










일반화와 특수화


범주의 계층

린네의 계층 구조는 좀 더 세부적인 범주가 계층의 하위에 위치하고 좀 더 일반적인 범주가 계층의 상위에 위치한다.

이때 계층의 상위에 위치한 범주를 계층의 하위에 위치한 범주의 일반화라고 하고, 계층의 하위에 위치한 범주는 계층의 상위에 위치한 범주의 특수화라고 한다.










서브타입

객체지향의 세계에서 범주는 개념을 의미하고, 개념은 타입을 의미하므로 일반화와 특수화는 계층 구조 안에 존재하는 타입 간의 관계를 의미한다.
슈퍼타입은 서브타입의 일반화이고 서브타입은 슈퍼타입의 특수화다.

  • 어떤 타입이 다른 타입보다 일반적이라면 이 타입을 슈퍼타입(supertype)이라고 한다.

  • 어떤 타입이 다른 타입보다 좀 더 특수하다면 이 타입을 서브타입(subtype)이라고 한다.










서브타입은 슈퍼타입의 본질적인 속성을 모두 포함하기 때문에 계층에 속하는 모든 서브타입들이 슈퍼타입의 속성을 공유한다는 것을 쉽게 예상할 수 있다.

일반화의 특징을 이용하면 부분적인 사실을 통해 복잡한 사실에 대한 논리적인 추론이 가능해진다.

객체의 집합을 나타내는 외연의 관점에서 서브타입은 슈퍼타입의 부분집합으로 표현된다.



크레이크 라만은 어떤 타입이 다른 타입의 서브타입이 되기 위해서는 '100% 규칙'과 'Is-a 규칙'을 준수해야한다고 말한다.

  • 두 타입이 100% 규칙과 Is-a규칙을 만족시키지 못할 경우 두 타입 간에 일반화 관계는 성립하지 않는다.

  • 100% 규칙

    • 슈퍼타입의 정의가 100% 서브타입에 적용돼야만 한다.

    • 서브타입은 속성과 연관관계 면에서 슈퍼타입과 100% 일치해야 한다.

  • Is-a 규칙

    • 서브타입의 모든 인스턴스는 슈퍼타입 집합에 포함돼야 한다.

    • 이는 대개 영어로 서브타입은 슈퍼타입이다(subtype is a supertype)라는 구문으로 테스트할 수 있다.

    • is-a 관계의 본질은 서브타입이 슈퍼타입의 부분집합이라는 것이다.










상속

일반화와 특수화 관계를 구현하는 가장 일반적인 방법은 클래스 간의 상속을 사용하는 것이다.
하지만 모든 상속 관계가 일반화 관계인 것은 아니다.
일반화의 원칙은 한 타입이 다른 타입의 서브타입이 되기 위해서는 슈퍼타입에 순응해야 한다는 것이다.

순응

  • 구조적 순응(structural conformance)

    • 기대 집합은 속성과 연관관계에 관한 것

    • 서브타입은 슈퍼타입이 가지고 있는 속성과 연관관계 면에서 100% 일치해야 한다.

    • 서브타입이 슈퍼타입을 대체하더라도 구조에 관한 동일한 기대 집합을 만족시킬 수 있다.

  • 행위적인 순응(behavioral conformance)

    • 기대 집합은 행위가 동일한 계약을 기반으로 하느냐에 관한 것

    • 타입의 행위에 관한 것이며, 서브타입은 슈퍼타입을 행위적으로 대체 가능해야 한다.

    • 흔히 리스코프 치환 원칙(Liskov Substitution)이라고 한다.



구조적 순응과 행위적인 순응 모두 특정 기대 집합에 대해 서브타입의 슈퍼타입에 대한 대체 가능성을 의미한다.





코드 재사용

상속의 또 다른 용도는 코드 중복을 방지하고 공통 코드를 재사용하기 위한 언어적 메커니즘을 제공하는 것이다.

상속하는 타입은 부모 클래스의 데이터와 메서드를 사용하고, 수정하고, 확장할 수 있다.










상속의 2가지 용도

모든 상속이 서브타이핑인 것은 아니다.
가능한 모든 상속 관계가 서브타이핑의 대체 가능성을 준수하도록 주의 깊게 사용하는 것은 코드를 유연하게 만들고 재사용성을 높이는 한 가지 방법이다.

  • 서브타이핑(subtyping)

    • 서브클래스가 슈퍼클래스를 대체할 수 있는 경우

    • 설계 유연성이 목표

    • 흔히 인터페이스 상속(interface inheritance)이라고 함

  • 서브클래싱(subclassing)

    • 서브클래스가 슈퍼클래스를 대체할 수 없는 경우

    • 코드의 중복 제거와 재사용이 목적

    • 흔히 구현 상속(implementation inheritance)이라고 함










위임(delegation)

여러 클래스로 구성된 상속 계층에서 수신된 메시지를 이해하는 기본적인 방법은 클래스 간의 위임을 사용하는 것이다.

어떤 객체의 클래스가 수신된 메시지를 이해할 수 없다면 메시지를 클래스의 부모 클래스로 위임한다.

클래스 간의 위임 사슬은 계층 내의 어떤 클래스가 메시지를 처리하거나 최상위 부모 클래스에 위임될 때까지 계속된다.










집합과 분해


계층적인 복잡성

  • 집합: 안정적인 형태의 부분으로부터 전체를 구축하는 행위

  • 분해: 집합과 반대로 전체를 부분으로 분할하는 행위

집합의 가치는 많은 수의 사물들의 형상을 하나의 단위로 다룸으로써 복잡성을 줄일 수 있다는 데 있다.

집합은 불필요한 세부 사항을 추상화한다.

전체와 부분 간의 일관된 계층 구조는 재귀적인 설계를 가능하게 한다.

집합은 전체의 내부로 불필요한 세부 사항을 감춰주기 때문에 추상화 메커니즘인 동시에 캡슐화 메커니즘이다.

집합과 분해는 한 번에 다뤄야 하는 요소의 수를 감소시킴으로써 인지 과부하를 방지한다.










합성 관계

객체와 객체 사이의 전체-부분 관계를 구현하기 위해서는 합성관계를 사용한다.

합성 관계는 부분을 전체 안에 캡슐화함으로써 인지 과부하를 방지한다.

객체들의 그룹과 관련된 복잡성이 완화된다.

단순한 물리적 통로가 존재한다는 사실만 나타내는 것을 연관 관계라고 한다.

합성 관계와 연관 관계 사이의 차이가 항상 명확한 것은 아니지만 일반적으로 합성 관계로 연결된 객체는 포함하는 객체가 제거될 때 내부에 포함된 객체도 함께 제거 된다.

이에 반해 연관 관계로 연결된 두 객체는 생명주기와 관련된 어떤 제약도 부과하지 않는다.

연관 관계로 연결된 두 객체는 독립적으로 제거될 수 있다.

합성 관계는 생명주기 측면에서 연관 관계보다 더 강하게 객체들을 결합한다.










패키지

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

패키지를 이용하면 시스템의 전체적인 구조를 이해하기 위해 한 번에 고려해야 하는 요소의 수를 줄일 수 있다.

개별 클래스가 아닌 클래스의 집합을 캡슐화함으로써 전체적인 복잡도를 낮출 수 있다.

함께 협력하는 응집도 높은 클래스 집합을 하나의 패키지 내부로 모으면 코드를 이해하기 위해 패키지 경계를 넘나들 필요가 적어진다.

패키지는 내부에 포함된 클래스들을 감춤으로써 시스템의 구조를 추상화한다.










참고 자료


조영호, 『객체지향의 사실과 오해』, 위키북스

0개의 댓글