Language/JAVA

다형성 (Polymorphism)

4Legs 2021. 3. 9. 23:22

스피커를 구매하자

 

스피커를 하나 구매하려는 상황을 가정해 보자. 우리가 고를 수 있는 제품은 A, B, C사에서 제조된 제품들이다.

우리는 어떤 제품을 사더라도, 음악을 재생할 수 있는 기능만 있다면 목표는 달성할 수 있다.

더 좋은 음질, 더 다양한 기능을 가진 제품을 구매할 수도 있지만, 아무튼 어떤 스피커를 사더라도 "음악을 듣는다" 라는 목표는 달성할 수 있을 것이다.

그런데, 우리가 스피커로 음악을 듣기 위해 스피커가 어떤 원리로 음악을 재생하는지 알 필요가 있을까?

물론 없다. 우리는 그저 스피커에서 나오는 음악을 듣기만 하면 된다.

우리가 구매했던 스피커에 음성 인식 기술이 새로 업데이트되었다!

만약 스피커에 어떤 부가적인 기능이 추가되거나 삭제되어도, "스피커로 음악을 듣는다" 라는 우리의 원래 목표는 변함이 없을 것이다. 이는 곧 스피커의 본질적인 역할이기 때문이다.

즉, 스피커의 제조사는 스피커로 음악을 듣는 사용자에게 영향을 끼치지 않으면서 다양한 기능을 업그레이드 할 수 있을 것이다. 

 

지금까지 살펴본 스피커 이야기가 곧 객체 지향에서의 다형성(Polymorphism)에 대한 이야기와 같다.

음악을 재생하는 스피커의 본질적인 기능이 곧 인터페이스와 같다. 이 인터페이스를 구현한 클래스들의 객체가 곧 실제 스피커가 된다.

즉, 인터페이스의 각 구현체들이 어떻게 구현되었는지와는 상관없이, 인터페이스에서 정의한 본질적인 역할만 고려하면 되도록 잘 설계하는 것이 중요하다 할 수 있다.

public interface Speaker{
	void PlayMusic(String MusicName);
}

예를 들어, 위와 같은 Speaker 인터페이스를 다음과 같은 클래스로 구현했다.

public class SpeakerA implements Speaker{
	@Override
	public void PlayMusic(String MusicName){
    	//(해당 음악을 찾는 로직)
        //(음악을 실제로 재생하는 로직)
        //...
    }
}

그리고 우리가 스피커를 사용하는 코드의 부분이 다음과 같다면,

Speaker speakerA = new SpeakerA();

public void UseSpeaker(String MusicName){
	speaker.PlayMusic(MusicName);
}

만약 SpeakerA 객체를 사용하다가 변경이 발생해 SpeakerB 객체를 사용해야 하는 상황이 오더라도, speaker 객체가 구현하는 클래스 명만 변경해주면 된다. 이처럼 실제로 코드에서 변경해야 할 부분을 최소화할 수 있다.

이처럼 객체를 설계할 때 해당 객체의 역할을 먼저 부여한 후, 그 역할을 수행하는 객체를 만드는 것이 좋다. 즉, 인터페이스를 우선적으로 만드는 것이 다형성을 활용하는 좋은 방법이라 할 수 있다.

 

 

참고 : 인프런 - "스프링 핵심 원리 - 기본편"