폴리모피즘을 이용한 설계가 빛을 발하게 됩니다.

폴리모피즘은 객체지향언어인 자바가 갖고있는 강력한 메커니즘 중의 하나로

폴리모피즘을 이용하면 실제 객체가 구체적으로 어떤 데이터형 인지를 몰라도 프로그램 할

수 있습니다.

구체적으로 표현하자면 Player클래스는 play 메소드를 정의할 때 메소드의 인자로 구체적인

데이터형으로 지정하지 않아도 된다는 뜻입니다.

예제 4 - 3 Player클래스에서 메소드 오버로딩을 사용한 경우는 public void play()

메소드에 전달되는 구체적인 악기의 데이터형(클래스형)을 메소드별로 일일이 적어

주어야 했습니다.다른 말로하면 어떤 데이터형을 사용할 것인지 미리 알고 있어야

한다는 뜻이고, 사용할 데이터형의 개수만큼 public void play()메소드를 만들어야 한다는

뜻입니다. 하지만 폴리모피즘을 이용한다면 public void play()메소드에 인자로 오는 객체가

어떤 데이터형인지 미리 알지 않아도 프로그램 할 수 있기 때문에 관계의 설정으로부터

자유로울 수 있으며 덕분에 아주 유연하고, 독립적인 프로그램이 가능해집니다.

독립적이다는 말은 악기가 10 100개 가 추가되더라도, Player 클래스에는 변경이 없어야

한다는 뜻입니다. 그래야만 악기클래스와 Player 클래스는 독립적인 것이지요.

 

생각을 조금 바꾸어 해보겠습니다.

연주자는 바이올린, 플룻, 피아노, 기타를 연주하는 것이 아니라 악기를 연주하는 것이고,

바이올린, 플룻,피아노,기타는 악기다라고 생각하는 것입니다.

, 하나의 층을 연주자와 악기 사이에 두는 것입니다. 그리고 그 만들어진 층만으로 의사

소통하는 것입니다. 이를 그림으로 표현한다면

 

사용자 삽입 이미지


그림 4 - 2 [ polymorphism ]

그림 4 - 2 를 살펴보면 Player클래스와 악기 클래스 사이에는 하나의 의사 소통을

담당하는 층(인터페이스)이 만들어 졌습니다. 그리고 Player는 그 의사소통을 담당하는 층과

관계를 가지고 있고, 악기들 또한 그 의사소통을 담당하는 층과만 관계를 가지고 있습니다.

여기서 의사소통을 담당하는 층을 인터페이스라고 합니다.

 

그림 4 - 2 Player클래스와 Instrument 인터페이스, 그리고 Instrument 인터페이스와

악기 클래스와의 관계를 보여주고 있습니다.

Player클래스는 Instrument 인터페이스와만 관계가 있고,Piano클래스,Guitar클래스,

Flute클래스,Violin클래스는 Instrument 인터페이스와만 관계가 성립됩니다.

화살표가 아래에서 위로 진행하는 것은 아래에 위치한 클래스가 해당 인터페이스를

구현한다는 뜻입니다.

 

Instrument 인터페이스에 대해서 좀더 설명하자면, Instrument 인터페이스는 Player클래스와

악기 클래스 사이에서 의사소통을 하는 층입니다.

Player클래스와 악기 클래스 사이에 필요한 인터페이스의 핵심은 Player클래스는 악기를

연주할 수 있다는 것이고, 바이올린,플룻,피아노 등은 소리를 내는 악기라는 개념입니다.

, 바이올린, 플룻,피아노등은 소리를 내는 악기라는 뜻이고, Player는 악기를 연주할 수

있다는 것입니다.

 

Instrument라는 인터페이스를 자바로 표현해보겠습니다. 인터페이스는 객체와 달라서

세상에 존재하는 객체가 아닙니다. 의사소통을 위해서 존재하는 가상의 개념이라고

생각하면 좋겠습니다.

 

인터페이스의 선언

 

package instrument;

/**

* 소리를 내는 악기를 의미합니다.

* 악기의 공통적인 행위인 소리를 내는 메소드를 선언합니다.

*/

public interface Instrument {             

 

                           public void sound();           // 메소드의 내용은 없습니다.                                  

}

예제 4 - 7 Instrument.java

클래스를 만들 때 class키워드를 사용하듯이 인터페이스는 만들때는 interface키워드를

사용합니다. 예제 4 - 7 Instrument 인터페이스는 interface 키워드를 사용했으므로

인터페이스입니다. Instrument 인터페이스는 instrument 패키지에 속해있고, public void

sound()메소드를 선언했습니다. 클래스에서는 흔한 멤버변수가 전혀 없습니다.

 일반적으로 인터페이스는 멤버변수를 가질수 없습니다. 객체와 같이 존재할 수 있는

것을 개념화 한 것이 아니라 단순히 의사소통의 기능만을 가지고 있는 존재이기 때문입니다.

인터페이스가 가질 수 있는 변수는 public static primitive형 데이터뿐입니다.

메소드 부분도 내용을 가질 수 없고, 다만 그 형태만 가지고 있습니다.

인터페이스는 메소드는 객체간 의사소통에만 사용되고,스스로 무엇을 하지는 않기때문

입니다.

 

 

 

인터페이스의 구현( implements 키워드)

 

일단 인터페이스가 만들어 졌다면 즉, Player와 연주악기들의 직접적인 관계를 인터페이스

를 통한 간접적인 관계로 만들어 낼 수 있습니다.

 

package instrument;

public class Flute implements Instrument {

             public void sound() {

                           System.out.println("play the flute");

             }

}

예제 4 - 8 Violin.java

 

예제 4 - 8 Violin.java는 예제 4 - 2에서 조금 변경되었습니다.

클래스 선언 부분에 implements 라는 키워드가 사용됬는데, implements 키워드는

클래스가 인터페이스를 구현할때 사용하는 키워드입니다.

클래스가 어떤 인터페이스를 구현한다고 할 때는 형식적으로는 클래스의 선언부분에

"implements 인터페이스"를 선언하고, 내용적으로는 인터페이스가 선언한 모든 메소드를

클래스에 정의해야 합니다. 예제 4 - 8 Violin 클래스는 형식적으로는 클래스 선언부에

"implements Instruement"라고 선언했고, 내용적으로는 Instrument 인터페이스에서

선언한 public void sound()와 꼭 같은 이름의 메소드를 구현했습니다.

이렇게 형식적인 것과 내용적인 것을 모두 갖추게 되면 Violin클래스는 Instrument

인터페이스를 구현한 클래스라고 할 수 있습니다.

 

package instrument;

public class Guitar implements Instrument {

             public void sound() {

                           System.out.println("play the guitar");

             }

}

예제 4 - 9 Guitar.java

 

예제 4 - 8 Violin.java와 예제 4 - 9 Guitar.java와 같이 악기클래스 모두 Instrument

인터페이스를 구현합니다. 모든 악기 클래스들은 그들의 근본적인 메소드인 public void

sound()메소드를 모두 구현한 상태이기 때문에 형식적으로 클래스 선언 부분에 "implement

Instrument"를 추가해 주면 됩니다.

 

이제 Player클래스를 새롭게 만들어 보겠습니다.

예제 4 - 3 Player클래스는 연주할 수 있는 구체적인 연주악기 마다 일일이 메소드를

정의해주었습니다. 물론 이런 방법의 설계가 불편하다는 것을 아셨을 것입니다.

Player클래스는 이제 악기(Instrument)를 연주하도록 수정될 것입니다.

 

import instrument.*;

 

public class GoodPlayer {

             public void play(Instrument i) {          // 악기를 연주합니다.

                           i.sound();

             }

             public static void main(String[] args) {

                           GoodPlayer player = new GoodPlayer();

                           player.play(new Guitar());   // 악기를 연주합니다.

                           player.play(new Violin());    // 악기를 연주합니다.

                           player.play(new Piano());    // 악기를 연주합니다.

                           player.play(new Flute());     // 악기를 연주합니다.

             }

}

예제 4 - 10 GoodPlayer.java

 

예제 4 - 10 GoodPlayer 클래스는 예제 4 - 3 Player 클래스와 형태적으로 많이 변화

했습니다. 일단 GoodPlayer클래스가 가지는 메소드가 단 한가지 뿐이라는 것입니다.

메소드 오버로딩을 통해 여러 개의 악기를 연주하는 Player클래스와는 달리

GoodPlayer클래스는 단 한 개의 메소드 뿐이고, 그 메소드도 구체적인 연주 악기인

Piano 라던가, Flute,Violin등이 아니라 마냥 두리 뭉실하게 보이는 Instrument 입니다.

GoodPlayer클래스의 메소드의 인자가 구체적인 Piano,Flute,Violin등의 클래스가 아니라

인터페이스인 Instrument를 가진다는 것은 아주 큰 의미가 있습니다.

GoodPlayer클래스의 public void play(Instrument i ) 메소드의 인자로 가질 수 있는

데이터형은 Instrument입니다. 하지만 Instrument는 인터페이스이므로 Instrument 객체는

세상에 존재할 수 없습니다. 그렇지만 Instrument인터페이스를 구현한 객체는 세상에

존재할 수 있는데 대표적으로 Guitar객체,Violin객체,Piano객체,Flute객체등입니다.

왜냐하면 Guitar클래스,Violin클래스,Piano클래스,Flute클래스 모두 Instrument 인터페이스를

구현했기 때문입니다. , 4개의 객체는 형식적으로는 모두 Instrument이기 때문입니다.

 


사용자 삽입 이미지

그림 4 - 3 [compile run (GoodPlayer.java)]

 

그림 4 - 3의 내용을 보면 실제 GoodPlayer에의 단 한 개의  메소드인 public void

play(Instrument i)는 인자로 들어온 객체의 종류에 따라 객체가 정의한 public void sound()

가 적절하게 호출된다는 것을 알 수 있습니다.

GoodPlayer public void play(Instruement i)에서 인터페이스의 메소드인 i.sound()

호출하게 되면 자바 버추얼머신이 실시간으로 인자로 바인딩된 객체의 종류를 파악하고

가장 적절한 메소드를 호출하기 때문입니다. , Instrument Violin이라면 Violin클래스에서

정의된 public void sound()를 호출하고 Instrument Flute이라면 Flute클래스에서 정의된

public void sound()를 호출해줍니다.

 

Posted by
,