하위 클래스를 상위 클래스의 데이터 타입으로 인스턴스화 했을 때 어떤 일이 일어나는지에 대해서는 어느정도 이해했을꺼라고 생각한다. 하지만 가장 큰 틀의 질문은 이걸 어디에 사용하는가?일것이다. 정당한 질문이다. abstract 수업의 예제 코드 를 조금 변경해보자.
package org .opentutorials .javatutorials .polymorphism ;
abstract class Calculator {
int left , right ;
public void setOprands (int left , int right ){
this .left = left ;
this .right = right ;
}
int _sum () {
return this .left + this .right ;
}
public abstract void sum ();
public abstract void avg ();
public void run (){
sum ();
avg ();
}
}
class CalculatorDecoPlus extends Calculator {
public void sum (){
System .out .println ("+ sum :" + _sum ());
}
public void avg (){
System .out .println ("+ avg :" + (this .left + this .right )/ 2 );
}
}
class CalculatorDecoMinus extends Calculator {
public void sum (){
System .out .println ("- sum :" + _sum ());
}
public void avg (){
System .out .println ("- avg :" + (this .left + this .right )/ 2 );
}
}
public class CalculatorDemo {
public static void main (String [] args ) {
Calculator c1 = new CalculatorDecoPlus ();
c1 .setOprands (10 , 20 );
c1 .run ();
Calculator c2 = new CalculatorDecoMinus ();
c2 .setOprands (10 , 20 );
c2 .run ();
}
}차이점은 아래와 같다. 아래는 예전 코드다.
아래는 변경된 코드의 내용이다.
차이점은 Calculator를 상속 받은 클래스들을 인스턴스화 할 때 Calculator를 데이터 타입으로 하고 있다. 이렇게 되면 인스턴스 c1과 c2를 사용하는 입장에서 두개의 클래스 모두 Calculator인 것처럼 사용할 수 있다. 예제를 조금 수정해보자.
package org .opentutorials .javatutorials .polymorphism ;
abstract class Calculator {
int left , right ;
public void setOprands (int left , int right ){
this .left = left ;
this .right = right ;
}
int _sum () {
return this .left + this .right ;
}
public abstract void sum ();
public abstract void avg ();
public void run (){
sum ();
avg ();
}
}
class CalculatorDecoPlus extends Calculator {
public void sum (){
System .out .println ("+ sum :" + _sum ());
}
public void avg (){
System .out .println ("+ avg :" + (this .left + this .right )/ 2 );
}
}
class CalculatorDecoMinus extends Calculator {
public void sum (){
System .out .println ("- sum :" + _sum ());
}
public void avg (){
System .out .println ("- avg :" + (this .left + this .right )/ 2 );
}
}
public class CalculatorDemo {
public static void execute (Calculator cal ){
System .out .println ("실행결과" );
cal .run ();
}
public static void main (String [] args ) {
Calculator c1 = new CalculatorDecoPlus ();
c1 .setOprands (10 , 20 );
Calculator c2 = new CalculatorDecoMinus ();
c2 .setOprands (10 , 20 );
execute (c1 );
execute (c2 );
}
}차이점은 아래와 같다.
클래스 CalculatorDemo의 execute 메소드는 CalculatorDecoPlus와 CalculatorDecoMinus 클래스의 메소드 run을 호출하면서 그것이 '실행결과'라는 사실을 화면에 표시하는 기능을 가지고 있다. 이 때 메소드 execute 내부에서는 매개변수로 전달된 객체의 메소드 run을 호출하고 있다.
만약 메소드 execute의 매개변수 데이터 타입이 Calculator가 아니라면 어떻게 해야할까? 위와 같은 로직을 처리 할 수 없을 것이다. 메소드 execute 입장에서는 매개변수로 전달된 값이 Calculator이거나 그 자식이라면 메소드 run을 가지고 있다는 것을 보장 받을 수 있게 되는 것이다.
이 맥락에서의 다형성이란 하나의 클래스(Calculator)가 다양한 동작 방법(ClaculatorDecoPlus, ClaculatorDecoMinus)을 가지고 있는데 이것을 다형성이라고 할 수 있겠다.