Archive

객체지향 상속의 종류: 서브클래싱과 서브타이핑 (Subclassing & Subtyping)

epicdev 2013. 4. 16. 10:38

출처: http://hyukmini.tistory.com/entry/%EC%84%9C%EB%B8%8C%ED%83%80%EC%9D%B4%ED%95%91Sub-Typing%EA%B3%BC-%EC%84%9C%EB%B8%8C%ED%81%B4%EB%9E%98%EC%8B%B1Sub-Classing


[요약]

서브클래싱은 구현되어 있는 클래스를 상속하는 것

서브타이핑은 정의되어 있는 인터페이스를 구현하는 것


두 의미를 살피기 전에 Class(클래스)와 Type(타입)의 의미를 짚고 넘어가겠습니다.

     Integer a = new Integer(7);

객체 a를 생성하기 위해 앞에 붙인 Integer를 부를 때 Class 혹은 Type 이라고 부릅니다. 우리는 무의식적으로 둘을 혼용해서 쓰고 있습니다. 차이점이 없는 것 같지만 둘은 차이가 존재하고 개발자는 이를 구분지을 수 있어야 상속을 통한 상황에 맞는 적절한 객체지향 프로그래밍을 구사할 수 있습니다.

클래스는 "객체가 수행할 행동에 대한 연산의 집합"으로 정의할 수 있습니다. 
클래스는 값을 저장할 변수와 행동에 대한 연산이 구현된 메소드들로 구성되어 있습니다. 

타입은 "객체가 수행할 행동에 대한 약속의 집합"으로 정의할 수 있습니다.
타입은 수행할 행동만 약속함으로써 메소드의 선언들로만 구성되어 있습니다.
Java, C# 같은 언어에서는 interface를 통해 타입을 정의할 수 있습니다.

이제 상속 이야기로 가볼까요? 객체지향에서는 2가지 상속 메카니즘이 존재합니다.
상속이란 부모와 자식이 존재할 때 자식이 자신의 행동과 부모의 행동을 받아들일 수 있는 관계를 뜻합니다.
상속은 클래스와 타입을 구분하듯이 클래스를 상속하는 Subclassing과 타입을 상속하는 Subtyping으로 구분됩니다.

Subclassing
Super Class(슈퍼 클래스)에 구현된 코드와 내부 표현 구조를 Sub Class(하위 클래스)가 이어받습니다.
클래스 상속으로 불리기도 하며 하위 클래스에서 슈퍼 클래스에 구현된 코드의 재사용이 가능합니다.

C#을 통해 서브클래싱(클래스 상속)의 예를 들어 보겠습니다.

class A  {
    public String Name()  {
        return "Class name is A";
    }
}
class B : A {
    public String Name() {
        return "Class name is B";
    }
}
public static void PrintName(A obj) {
    Console.WriteLine(obj.Name());
}
static void Main(string[] args) {
    A objA = new A();
    A objB = new B();
    PrintName(objA);   => Class name is A   - (1)
    PrintName(objB);   => Class name is A   - (2)
}

(2)의 결과는 예상과 조금 다르게 나옵니다.  클래스 상속은 부모 클래스의 코드를 재사용하기 때문에 위와 같이 슈퍼클래스의 객체를 하위클래스의 객체로 대체하더라도 하위 클래스의 행동으로 대체되어 동작하지 않습니다. 이는 메소드 재정의(method overriding)를 통해 부모 클래스의 메소드를 대체하여야 합니다. C#에서는 부모에는 virtual 키워드를 넣어 가상함수로 정의하고 자식에는 override 키워드를 넣어 메소드 구현을 재정의를 합니다.

class A  {
    public virtual String Name()  {
        return "Class name is A";
    }
}
class B : A {
    public override String Name() {
        return "Class name is B";
    }
}


Subtyping
Super Type(슈퍼 타입)의 객체가 수행할 행동의 약속을 Sub Type(서브 타입)이 이어받습니다. 행동들을 공통된 타입으로 묶어 Runtime에 슈퍼 타입의 객체를 서브 타입의 객체로 대체가 가능하도록 해줍니다. 이를 통해 프로그램 변경에 대한 영향을 최소화하여 변경에 대한 유연한 대처가 가능토록 제공합니다.
 
C#을 통해 인터페이스를 통한 서브타이핑의 예를 들어 보겠습니다.

interface MyClass  {
    String Name();
}
class A : MyClass {
    public String Name()  {
        return "Class name is A";
    }
}
class B : MyClass {
    public String Name() {
        return "Class name is B";
    }
}
public static void PrintName(MyClass obj) {
    Console.WriteLine(obj.Name());
}
static void Main(string[] args) {
    MyClass objA = new A();
    MyClass objB = new B();
    PrintName(objA);   => Class name is A   - (1)
    PrintName(objB);   => Class name is B   - (2)
}

인터페이스 상속은 부모 타입의 행동의 약속만 상속받습니다. (C#에서 인터페이스에 메소드만 기술할 수 있습니다.) 따라서 슈퍼타입의 객체를 하위타입의 객체로 대체하면 동적으로 하위 타입의 행동으로 대체되어 호출이 됩니다.