2016년 9월 30일 금요일

상속(inheritance)과 속성(component)

OOP언어의 특징 중 하나가 '상속(inheritance)'입니다. 주로 다형성(Polymorphism) - 다른 객체를 동일하게 취급하기 위해 사용합니다.

그런데 실제로 상속을 사용하다 보면 오히려 더 어려운 코드가 만들어지는 경우가 있습니다.

만약 동물의 왕국을 상속을 통해 만든다면...
public class Animal
{
    public virtual void Bite()
    {
        // do Nothing
    }
    public virtual void Swim()
    {
        // do Nothing
    }
    public virtual void Run()
    {
        // do Nothing
    }
    public virtual void Fly()
    {
        // do Nothing
    }
}

public class Avian : Animal
{
    public override void Fly()
    {
        // do Fly
    }
}

public class Mammal : Animal
{
}


public class Seagal : Avian
{
}

public class Penguin : Avian
{
    public override void Swim()
    {
        // do Swim
    }
    public override void Fly()
    {
        // do Nothing - Avian은 날 수 있는데 Penguin은 날지 못하므로
    }
}

public class Ostrich : Avian
{
    public override void Run()
    {
        // do Run
    }
    public override void Fly()
    {
        // do Nothing - Avian은 날 수 있는데 Ostrich는 날지 못하므로
    }
}

public class Bat : Mammal
{
    public override void Fly()
    {
        // do Fly
    }
}

public class Whale : Mammal
{
    public override void Swim()
    {
        // do Swim
    }
}

public class Dog : Mammal
{
    public override void Bite()
    {
        // Do bite
    }
    public override void Run()
    {
        // do Run
    }
}


.....
List<Animal> Zootopia = new List<Animal>();

Zootopia.Add(new Penguin());
Zootopia.Add(new Seagal());
Zootopia.Add(new Ostrich());
Zootopia.Add(new Bat());
Zootopia.Add(new Dog());
Zootopia.Add(new Whale());

이정도가 될 수 있겠죠. 전체적으로 정돈되지 않고, 중복되는 코드(While.Swim(), Penguin.Swim()), 복잡한 가상함수관계(Animal.Fly(), Avian.Fly(), Ostrich.Fly(), Bat.Fly()), 그리고 덩치가 큰 base 클래스(class Animal) 등에 의해 알아보기 힘든 코드가 됩니다.

이런 단점을 보완하기 위해서 컴포넌트(Component)를 사용할 수 있습니다. 상속관계를 본체(Animal)가 아니라 컴포넌트에 적용하는 것입니다.

// Components
public class Component
{
    public virtual void Do
    {
        // do Nothing
    }
}

public class Bite : Component
{
    public override void Do
    {
        // do Bite
    }
}

public class Swim : Component
{
    public override void Do
    {
        // do Swim
    }
}

public class Run : Component
{
    public override void Do
    {
        // do Run
    }
}

public class Fly : Component
{
    public override void Do
    {
        // do Fly
    }
}




public class Animal : List<Component>
{
}

public class Avian : Animal
{
    Add(new Fly());  // 조류의 경우는 기본적으로 날아다님
}

public class Mammal : Animal
{
}


public class Seagal : Avian
{
    public Seagal()
    {
    }
}

public class Penguin : Avian
{
    public Penguin()
    {
        Add(new Swin());
        RemoveFly();     // 리스트에서 Fly 제거
    }
}

public class Ostrich : Avian
{
    public Ostrich()
    {
        Add(new Run());
        RemoveFly();     // 리스트에서 Fly 제거
    }
}

public class Bat : Mammal
{
    public Bat()
    {
        Add(new Fly());
    }
}

public class Whale : Mammal
{
    public Whale()
    {
        Add(new Swim());
    }
}

public class Dog : Mammal
{
    public Dog()
    {
        Add(new Bite());
        Add(new Run());
    }
}


.....
List<Animal> Zootopia = new List<Animal>();

Zootopia.Add(new Penguin());
Zootopia.Add(new Seagal());
Zootopia.Add(new Ostrich());
Zootopia.Add(new Bat());
Zootopia.Add(new Dog());
Zootopia.Add(new Whale());

이렇게 각자가 가진 속성만 정의하면 되므로 가독성이 높아질 수 있습니다.