다형성이란?

gwjeon·2021년 9월 19일
1


학습참조
인프런-스프링 핵심 원리 기본편(김영한님)


✅ 다형성이란?

다형성이란 여러개의 형태를 가질 수 있다는 의미이다.

프로그램 언어의 다형성(多形性, polymorphism; 폴리모피즘)은 그 프로그래밍 언어의 자료형 체계의 성질을 나타내는 것으로, 프로그램 언어의 각 요소들(상수, 변수, 식, 오브젝트, 함수, 메소드 등)이 다양한 자료형(type)에 속하는 것이 허가되는 성질을 가리킨다. 반댓말은 단형성(monomorphism)으로, 프로그램 언어의 각 요소가 한가지 형태만 가지는 성질을 가리킨다. [위키백과]

주목해야 할 부분은 프로그램 언어의 각 요소들이 다양한 자료형에 속하는 것이 허가 되는 성질을 가르킨다는 것이다. 프로그래밍에서 다형성이란 하나의 부모타입 참조변수가 여러 자식 타입의 인스턴스를 가질 수 있는것을 말하며 객체지향 프로그래밍에서 가장 중요시 되는 핵심이 바로 다형성이다.


✅ 다형성의 특징

  • 하나의 부모타입이 여러 자식타입을 가질 수 있다.
  • 유연하고 변경에 용이하다.
  • 확장성이 뛰어나다.

✅ 실세계에 비유한 다형성(Taxi)

  • 역할과 구현으로 구분한다.
  • 역할은 인터페이스이며 구현은 클래스이다.
  • 역할은 Taxi가 되며, 구현은 아반떼, 소나타, 그랜저가 된다.
  • Taxi Driver는 Taxi의 차가 아반떼이던, 소나타, 그랜저 차량의 종류와 상관없이 업무를 수행 할 수 있다.
  • Taxi Driver는 대상의 역할(Taxi 인터페이스)만 알면 됨.
  • Taxi Driver는 구현 대상(Avante, Sonata, Grandeur 클래스)의 내부 구조를 알 필요가 없음.
  • Taxi Driver는 구현 대상의 내부 구조가 변경되어도 영향을 받지 않음.
  • Taxi Driver는 구현 대상 자체를 변경하여도 영항을 받지 않음.


✔ 소스코드로 비교

  • Main
public class Main {
    public static void main(String[] args) {
        TaxiDriver taxiDriver = new TaxiDriver(new Avante());
        taxiDriver.run(); // --> output: 100km까지 걸리는 시간은 8초
        taxiDriver.stop(); // --> output: 100km에서 0km까지 걸리는 시간은 5초
        taxiDriver.guestDropOff(); // --> output: 손님 하차
    }
}
  • Taxi 인터페이스
public interface Taxi {
    public void stepOnAccelerator();
    public void stepOnBrake();
}
  • 아반떼 구현 클래스
public class Avante implements Taxi {
    @Override
    public void stepOnAccelerator() {
        System.out.println("100km까지 걸리는 시간은 8초");
    }

    @Override
    public void stepOnBrake() {
        System.out.println("100km에서 0km까지 걸리는 시간은 5초");
    }
}
  • 소나타 구현 클래스
public class Sonata implements Taxi {
    @Override
    public void stepOnAccelerator() {
        System.out.println("100km까지 걸리는 시간은 6초");
    }

    @Override
    public void stepOnBrake() {
        System.out.println("100km에서 0km까지 걸리는 시간은 4초");
    }
}
  • 그랜저 구현 클래스
public class Grandeur implements Taxi {
    @Override
    public void stepOnAccelerator() {
        System.out.println("100km까지 걸리는 시간은 5초");
    }

    @Override
    public void stepOnBrake() {
        System.out.println("100km에서 0km까지 걸리는 시간은 3초");
    }
}
  • Taxi Driver 클래스
public class TaxiDriver {
    private Taxi taxiCar;
    
    public TaxiDriver(Taxi taxiCar) {
        this.taxiCar = taxiCar;
    }
    
    // 달리다
    public void run() {
        taxiCar.stepOnAccelerator();
    }
    
    // 멈추다
    public void stop() {
        taxiCar.stepOnBrake();
    }

    public void guestDropOff() {
        System.out.println("손님 하차");
    }
}

택시기사는 택시의 차 종류가 무엇이던 간에 운전을 할 수 있고 택시 업무를 수행 할 수 있다. 즉 택시가 무엇으로 바뀌던지 간에 유연하고 변경에 용이하게 대응 할 수 있다. 왜냐하면 택시기사는 기본적으로 아반떼나, 소나타, 그랜저의 구현체에 의존성을 가지는것이 아닌 Taxi 인터페이스라는 역할에 의존성을 가지기 때문이다.

만약 차량이 고장날 경우에 대비하여 택시가 아반떼가 아닌 소나타나 그랜저로 바뀌어야 한다면 택시기사는 아반떼가 아닌 소나타나 그랜저를 운전하여 택시 업무를 수행하면 그만이다. 이 역시 소스코드에서도 쉽게 대응 가능하다. Main 함수에서 아래와 같은 수정만 이루어 지면 된다.

public class Main {
    public static void main(String[] args) {
        //TaxiDriver taxiDriver = new TaxiDriver(new Avante());
        //TaxiDriver taxiDriver = new TaxiDriver(new Sonata());
        TaxiDriver taxiDriver = new TaxiDriver(new Grandeur());
        taxiDriver.run();
        taxiDriver.stop();
        taxiDriver.guestDropOff();
    }
}

TaxiDriver의 생성자 함수로 인스턴스만 Avante의 구현체가 아닌 Sonata나 Grandeur을 넣어주면 된다. 이렇게 하면 TaxiDriver의 생성자에서

public class TaxiDriver {
    private Taxi taxiCar;
    
    public TaxiDriver(Taxi taxiCar) {
        this.taxiCar = taxiCar;
    }

다음과 같이 Taxi 인터페이스를 Parameter로 전달 받아 taxiCar 멤버 변수에 할당한다. 앞서 Avante와 Sonata, Grandeur 구현 클래스는 Taxi 인터페이스를 구현(상속)하고 있기 때문에 이와 같은 행위가 가능하다. 아까 위에서 설명했듯 다형성이란 하나의 부모타입 참조변수가 여러 자식 타입의 인스턴스를 가질 수 있다. 즉 Avante와 Sonata, Grandeur 구현 클래스의 부모타입이 Taxi 인터페이스가 되는 것이다.

위에서 택시 차량이 아반떼에서 소나타로 변경되고, 그랜저로 변경 될 때 이러한 다형성의 특성을 이용하여 택시 차량이 바뀌어도 다른것은 전~~~혀 손댈 필요 없고 TaxiDriver 객체의 Taxi만 변경 해주면 되니 이 얼마나 편리하고 유연하고 변경에 용이한가? 심지어 Taxi 인터페이스를 상속받아 벤츠, BMW, 아우디, 테슬라등 어떠한 자동차던지 만들어 낼 수 있다. 이 얼마나 확장성이 좋은가?


✔ 또 다른 실세계와 비유한 다형성의 예시

  • 키보드와 마우스, 모니터, 프린터등 주변기기들
  • 운동기구(운동기구가 뭐든 간에 운동을 하는것은 변함 없음)
  • 정렬 알고리즘(퀵,선택,삽입등 정렬 알고리즘은 다양하지만 정렬을 한다는것은 변함 없음)
  • 기타 등등...

✅ 정리하며

구현(상속) 받는 부모타입의 참조변수를 통해 자식의 인스턴스를 가짐으로써 유연하고 변경에 용이한 프로그래밍을 구현 할 수 있다. 택시기사 입장에서는 택시 영업을 할 수 있는 면허와 자동차만 있으면 차가 무엇이든 간에 언제든지 택시 업무를 수행 할 수 있는 것이다. 차가 바뀌던 말던간에 자동차는 엑셀을 밟으면 출발하고 브레이크를 밟으면 멈추는 기능은 모두가 동일하기 때문에 택시기사가 운전을 할 수 있다는 사실은 변함이 없기에 전혀 상관이 없다. 이것이 바로 다형성의 강력함이다.

profile
ansuzh

0개의 댓글