오브젝트 리뷰 - 7

카테고리 없음 2021. 8. 29. 13:34 Posted by 아는 개발자

다형성

 

다형성 

 

강제다형성은 언어가 지원하는 자동적인 타입 변환이나 사용자가 직접 구현한 타입 변환을 이용해 동일한 연산자를 다양한 타입에 사용할 수 있는 방식을 가리킨다.

 

매개변수 다형성은 제너릭 프로그래밍과 관련이 높은데 클래스의 인스턴스 변수나 메서드의 매개변수 타입을 임의의 타입으로 선언한 후 사용 시점에 구체적인 타입으로 지정하는 방식을 가리킨다. 

 

포함 다형성은 메시지가 동일하더라도 수신한 객체의 타입에 따라 실제로 수행되는 행동이 달라지는 능력을 말한다. 객체지향 프로그래밍에서 가장 널리 알려진 형태의 다형성이다. 포함다형성을 위한 전제 조건은 자식 클래스가 부모 클래스의 서브타입이어야 한다는 것이다. 상속의 진정한 목적은 코드 재사용이 아니라 닿령성을 위한 서브타입 계층을 구축하는 것이다

 

상속의 양면성 

 

상속의 목적은 코드 재사용이 아니라 프로그램을 구성하는 개념들을 기반으로 다형성을 가능하게 하는 타입 계층을 구축하기 위한 것이다. 타입 계층에 대한 고민 없이 코드를 재사용하기 위해 상속을 사용하면 이해하기 어렵고 유지보수하기 버거운 코드가 만들어질 확률이 높다. 

 

자식 클래스 안에 상속받은 메서드와 동일한 시그니처의 메서드를 재정의해서 부모 클래스의 구현을 새로운 구현으로 대체하는 것을 메서드 오버라이딩이라고 하고 부모 클래스에서 정의한 메서드와 이름은 동일하지만 시그니처는 다른 메서드를 자식 클래스에 추가하는 것을 메서드 오버로딩이라고 부른다. 

 

업캐스팅과 동적 바인딩 

 

부모 클래스 타입으로 선언된 변수에 자식 클래스의 인스턴스를 할당하는 것이 가능하다. 이를 업캐스팅이라고 한다. 

 

선언된 변수 타입이 아니라 메시지를 수신하는 객체의 타입에 따라 실행되는 메서드가 결정된다. 객체지향 시스템이 메시지를 처리할 적절한 메서드를 컴파일 시점이 아니라 실행 시점에 결정하기 때문이다. 이를 동적 바인딩이라고 한다. 

 

반대로 코드를 작성하는 시점에 호출할 코드가 결정되는 경우. 컴파일 타임에 호출할 함수를 결정하는 방식을 정적 바인딩 또는 컴파일타임 바인딩이라고 부른다. 

 

상속대 위임 

 

자신이 수신한 메시지를 다른 객체에게 동일하게 전달해서 처리를 요청하는 것을 위임(delegation)이라고 부른다. 위임은 본질적으로 자신이 정의하지 않거나 처리할 수 없는 속성 또는 메서드의 탐색 과정을 다른 객체로 이동시키기 위해 사용한다. 이를 위해 위임은 항상 현재의 실행 문맥을 가리키는 self 참조를 인자로 전달한다. 이것이 self 참조를 전달하지 않는 포워딩과 위임의 차이점이다.

 

서브클래싱과 서브타이핑

 

타입 

 

프로그래밍 언어의 관점에서 타입은 호출 가능한 오퍼레이션의 집합을 정의한다. 객체지향 프로그래밍에서 오퍼레이션은 객체가 수신할 수 있는 메시지를 의미한다. 따라서 객체의 타입이란 객체가 수신할 수 있는 메시지의 종류를 정의하는 것이다. 객체지향 프로그래밍에서 타입을 정의하는 것은 객체의 퍼블릭 인터페이스를 정의하는 것과 동일하다.

 

타입 계층 

 

타입 계층을 구성하는 두 타입 간의 관계에서 더 일반적인 타입을 슈퍼타입이라고 부르고 더 특수한 타입을 서브타입이라고 부른다. 객체지향 프로그래밍에서 객체의 타입을 결정하는 것은 퍼블릭 인터페이스다. 일반적인 타입이란 비교하려는 타입에 속한 객체들의 퍼블릭 인터페이스보다 더 일반적인 퍼블릭 인터페이스를 가지는 객체들의 타입을 의미한다. 

 

서브클래싱과 서브타이핑

 

타입 계층의 의미는 행동이라는 문맥에 따라 달라질 수 있다. 올바른 타입 계층이라는 의미 역시 문맥에 따라 달라질 수 있다. 따라서 슈퍼타입과 서브타입 관계에서는 is-a 보다 행동 호환성이 더 중요하다. 어떤 두 대상이 is-a 라고 표현할 수 있더라도 상속을 사용할 예비후보 정도로만 생각해야한다. 

 

타입의 이름 사이에 개념적으로 연관성이 있다고 하더라도 행동에 연관성이 없다면 is-a 관계를 사용하지 말아야 한다. 행동 호환 여부를 판단하는 기준은 클라이언트 관점이다. 클라이언트 관점에서 두 타입이 동일하게 행동할 것이라고 기대한다면 두 타입을 타입 계층으로 묶을 수 있다. 그렇지 않다면 두 타입을 타입 계층으로 묶어서는 안된다. 

 

서브클래싱은 다른 클래스의 코드를 재사용할 목적으로 상속을 사용하는 경우를 가리킨다. 구현상속 또는 클래스상속이라고 부른다. 서브타이핑은 타입 계층을 구성하기 위해 상속을 사용하는 경우를 가리킨다. 부모 클래스는 자식 클래스의 슈퍼타입이 되고 자식 클래스는 부모 클래스의 서브타입이 된다. 인터페이스 상속이라고 부르기도 한다.  서브타이핑과 서브클래싱을 나누는 기준은 상속을 사용하는 목적이다. 

 

서브타이핑 관계가 유지되기 위해서는 서브타입이 슈퍼타입이 하는 모든 행동을 동일하게 할 수 있어야 한다. 어떤 타입이 다른 타입의 서브타입이 되기 위해서는 행동호환성을 만족시켜야 한다. 

 

리스코프 치환 원칙 

 

올바른 상속 관계의 특징을 정의하기 위해 리스코프 치환원칙이 있다. 자식 클래스가 부모 클래스와 행동 호환성을 유지함으로써 부모 클래스를 대체할 수 있도록 구현된 상속관계만을 서브타이핑이라고 볼 수 있다. 

 

상속관계는 클라이언트 관점에서 자식 클래스가 부모 클래스를 대체할 수 있을때만 올바르다.  is-a 관계는 객체지향에서 중요한 것은 객체의 속성이 아니라 객체의 행동이라는 점을 강조한다. 

728x90