lang/java

java 다형성(Polymorphism)

C/H 2007. 6. 20. 04:22

다형성(Polymorphism)

다형성이란 객체지향에 있어서 가장 포괄적인 개념이다. 추상화능력이나 상속같은 경우는 'A는 B이다'라는 식의 정의가 가능했지만 다형성은 'A는 B이다'와 함께 'A는 C도 될 수 있다'라는 다분히 확장적인 개념이다. 다형성이란 다분히 객체와 관련되 개념이므로 실제 세계를 프로그램으로 옮기는 동안 다형성을 자연스럽게 깨닫게 될 것이다.

다형성의 개년 - has a relationship
상속이 다분히 객체 타입과 관련된 것과는 달리, 다형성은 객체의 동작과 많은 관련이 있다. 하나의 예를 들어서 '~을 열다(open)'라는 동작을 생각해 보면 열다라는 의미가 얼마나 다른 의미로 사용될수 있는지 알 수 있다.

* 창문을 열다
* 상자를 열다
* 대문을 열다

자바에서는 객체를 상속하는 경우에 명확하게 extends를 이용하는 단일 상속만을 지원하고 있기 때문에 하나의 동작에 대해서 다양한 형태를 수행하기 위해서는 다중 상속을 지원할 만한 방식이 필요하다. 자바에서 인터페이스(interface)는 이러한 자바의 단일 상속의 문제를 해결하고 있다.

인터페이스 형태
자바에서의 인터페이스는 원래 추상 클래스의 변형된 형태이므로 다음과 같이 구성된다. 가장 주의해야 할 것은 추상 클래스와 마찬가지로 인터페이스 역시 new를 이용한 객체 생성을 할 수 없다.

(접근제한자) interface (알을 낳을 수 있는 종류) {
    알을 낳을 수 있는 종류가 공통적으로 가지고 있는 행동 - 알낳기();
}

주의해야 할 것은 알을 낳을 수 잇는 여러 동물(닭, 개구리, 물고기)은 자신만의 방식으로 알을 낳기 때문에 추상 메소드의 형태로 해두어서 각 동물에 맞게 재 정의하도록 한다는 것이다.

예>
[code type=java]
public interface LayingEgg{
    int AAA = 2; // 인터페이스의 변수는 상수가 되어 버리므로 주의한다.
    public void layEgg(); // 추상메소드의 형태 사용
}
[/code]

인터페이스를 이요한는 클래스는 'implements'라는 키워드를 사용한다.(보통 인터페이스를 구현한다고 표현한다).

예> class Platypus extends Mammal implements LayingEgg { }
      // 표유류를 상속받고, 알을 낳을 수 잇는 타입인 오리너구리 클래스

상속과 달리 인터페이스는 여러 개를 구현할 수 있다. 이 때는 ','를 써서 구분한다.

예> class A implement 인터페이스A, 인터페이스B, 인터페이스C { }

실제로 오리너구리라는 것을 크래스로 만들어 보겠다.
1. 우선은 포유류이므로 포유류 Mammal 클래스를 만들고
2. 알을 낳는다는 LayingEgg를 인터페이스로 만들고
3. 마지막으로 오리너구리를 만든다.

[code type=java]
// Mammal.java
class Mammal{
    public void growByMilk(){
        System.out.println("모든 포유류는 젖먹이 동물이다.");
    }
}

// LayingEgg.java
public interface LayingEgg{
    int AVERAGE_EGGS = 2; // final static으로 선언되지 않았다.
    public void layAnEgg();  // 인터페이스의 모든 메소드는 추상 메소드 이다.
}

//Platypus.java
class Platypus extends Mammal implements LayingEgg{
    String name;

    public Platpus(String n){
        name = n;
    }

    public void layAnEgg(){
        System.out.pringln(name +"는 알을 "+ AVERAGE_EGGS +"개 낳는다");
    }

    public static void main(String[] args){
        Playpus p1 = new Platypus("오리너구리");
        p1.growByMilk(); // 포유류의 동작
        p2.layEgg();        // 인터페이스의 동작
    }
}
[/code]

클래스와 같은 역활을 하는 인터페이스
인터페이스가 중요한 또 다른 이유는 인터페이스가 클래스처럼 어떤 객체들의 타임으로 사용될 수 있기 때문이다. 지금까지 클래스는 상속 받는 비슷한 종류를 의미해서 다음과 같이 사용했다.

Person p = new Student(); // 누가 봐도 그럴듯한 관계인 경우 상속을 허용

인터페이스의 경우는 상속과는 전혀 다른 방식으로도 사용할 수 있다. 만약 오리너구리와 공룡 클래스 모두가 implements LayingEgg하고 있다면

LayingEgg p1 = new 오리너구리();
LayingEgg p2 = new 공룡();          // 전형 연관관계가 없어 보이는 클래스

위와 같이 사용하는 것이 가능하다.

앞에서 언급한 열다(open)이라는 동작을 구현하는 클래스를 만들어 보자
[code type=java]
// OpenAble.java
public interface OpenAble{
    public void open(); // 추상 매소드 OpenAble을 구현하는 클래스들은 반드시 'open();'메소드를 만들어야 한다.
}

// Windows.java
class Windows implements OpenAble{
    public void acceptLight(){
        System.out.println("창은 햇빛을 받아들인다.");
    }

    // interface 의 추상 메소드 open
    public void open(){
        System.out.println("공기를 들어오게 한다.");
    }
}

// Box.java
class Box implements OpenAble{
    public void boxing(){
        System.out.println("박스를 이용해 포장한다.");
    }

    // interface 의 추상메소드 open
    public void open(){
        System.out.println("물건을 꺼내기 위해서 박스를 연다");
    }
}

// Door.java
class door implements OpenAble{
    public void out(){
        System.out.println("방에서 나간다. ");
    }

    // interface 의 추상메소드 open
    public void open(){
        System.out.println("방에 들어간다.");
    }
}

// OpenTest.java
class OpenTest{
    public static void main(String[] args){
        OpenAble[] opens = { new Door{}, new Windows(), new Box() }; // 문을 열수 잇는 타입의 객체들 = { 문, 창문, 박스 };
        for(int i = 0; i<OpenAble.length; i++){
            System.out.println("-----------------------------------");
            opens[i].open();
        }
    }
}
[/code]

반응형