본문 바로가기
카테고리 없음

[JAVA] 다형성이란

by Jayce_choi 2021. 7. 3.
반응형

다형성 (Polymorphism) : 하나의 코드가 여러 자료형으로 구현되어 실행되는 것을 의미합니다. 좀 더 쉽게 의미한다면 실행 결과가 여러 가지로 나오는 것입니다. 

그림과 같이 3개의 클래스가 Animal 클래스를 상속받고 있다. 이때 Animal 클래스에서도 메서드 하나를 정의하고 상속받은 클래스에서 재정의를 수행하는데 이를 코드로 구현해봅시다. 

package polymorphism;

class Animal {
	public void move() {
		System.out.println("동물이 움직입니다.");
	}
}

class Human extends Animal {
	public void move() {
		System.out.println("사람이 두 발로 걷습니다. ");
	}
}

class Tiger extends Animal {
	public void move() {
		System.out.println("호랑이가 네발로 뜁니다.");
	}
}
class Eagle extends Animal {
	 public void move() {
		 System.out.println("독수리가 하늘을 납니다. ");
	 }
}

public class AnimalTest1 {
	public static void main(String[] args) {
		AnimalTest1 aTest = new AnimalTest1();
		aTest.moveAnimal(new Human());
		aTest.moveAnimal(new Tiger());
		aTest.moveAnimal(new Eagle());
	}
	public void moveAnimal(Animal animal) {
		animal.move();
	}
}

테스트를 위해서 AnimalTest 클래스에서 moveAnimal() 메서드를 만들었습니다. 이 메서드는 어떤 인스턴스가 매개변수로 넘어와도 모두 Animal 형으로 변환을 합니다. 예를 들어서 매개변수가 전달되는 부분에 Human 인스턴스가 전달되었다면 다음 코드처럼 형 변환 됩니다.

Animal에서 상속받은 클래스가 매개변수로 넘어오면서 모두 Animal 형으로 변환이 되었고 Animal 형으로 변하였기 때문에 animal.move() 메서드를 호출할 수가 있었습니다. 가상 메서드 원리에 의해서 animal.move() 메서드가 호출하는 메서드는 Animal의 move가 아닌 매개변수로 넘어온 실제 인스턴스의 메서드입니다. animal.move() 코드는 변함이 없지만 어떤 매개변수가 넘어왔느냐에 따라서 출력문이 달라지게 되는데 이것이 바로 다형성입니다.

 

다형성의 장점

다른 동물이 새로 추가되었을 경우를 생각해볼 때 새로운 동물들도 Animal 클래스를 상속받아 구현하게 되면 모든 클래스를 Animal 자료형 하나로 쉽게 관리가 가능할 것입니다. 이것이 다형성을 활용한 프로그램의 확장성입니다. 각 자료형에 따라서 코드를 다르게 구현한다면 코드는 훨씬 복잡해지고 내용이 길어질 수가 있는데 이처럼 상위 클래스에서 공통부분의 메서드를 제공하고 하위 클래스에서는 이에 기반하여 추가 요소만 덛붙여 진다면 코드의 양이 줄어들며 유지보수도 편리하게 됩니다.

또 필요에 의해서 상속받은 모든 클래스를 하나의 상위 클래스로 처리할 수 있고 다형성에 의해 각 클래스의 여러 가지 구현이 가능하므로 프로그램을 쉽게 확장이 가능해집니다.

정리 : 다형성을 잘 활용만 한다면 유연하고 구조화된 코드를 구현하여 확장성 있고 유지보수하기 좋은 프로그램을 개발 가능합니다.

 

 

이전에 했던 Customer 코드에서도 다형성을 적용해보도록 하겠습니다.

전체 코드 구성은 Customer, VIPCustomer, 그리고 메인 문이 포함된 CustomerTest 클래스로 총 3개의 클래스로 구성되어있습니다.

1. customer 클래스 코드 

package polymorphism;

public class Customer {
	protected int customerID;
	protected String customerName; 
	protected String customerGrade; 
	int bonusPoint;
	double bonusRatio;
	
	public Customer() {
		initCustomer();
	}
	
	public Customer(int customerID, String customerName) {
		this.customerID = customerID;
		this.customerName = customerName;
		initCustomer();
	}
	
	private void initCustomer() { // 생성자에서만 호출하는 메서드이므로 private으로 선언 ( 멤버 변수의 초기화 부분 ) 
		customerGrade = "SILVER";
		bonusRatio = 0.01;
	}
	
	public int calcPrice(int price) {
		bonusPoint += price * bonusRatio; 
		return price; 
	}
	
	public String showCustomerInfo() {
		return customerName + " 님의 등급은 " + customerGrade + "이며, 보너스 포인트는" + bonusPoint +"입니다.";
	}

	public int getCustomerID() {
		return customerID;
	}
	public void setCustomerID(int customerID) {
		this.customerID = customerID;
	}
	public String getCustomerName() {
		return customerName;
	}
	public void setCustomerName(String customerName) {
		this.customerName = customerName;
	}
	public String getCustomerGrade() {
		return customerGrade;
	}
	public void setCustomerGrade(String customerGrade) {
		this.customerGrade = customerGrade;
	}
	
}

 

2. VIPCustomer 클래스 코드 

package polymorphism;

public class VIPCustomer extends Customer {
	private int agentID;
	double saleRatio;
	
	public VIPCustomer(int customerID, String customerName, int agentID) {
		super(customerID, customerName);
		customerGrade = "VIP";
		bonusRatio = 0.05;
		saleRatio = 0.1; 
		this.agentID = agentID;
	}
	public int calcPrice(int price) {
		bonusPoint += price * bonusRatio;
		return price - (int)(price * saleRatio);
	}
	
	public String showCustomerInfo() {
		return super.showCustomerInfo() + "담당 상담원 번호는 " +agentID + "입니다.";
	}
	public int getAgentID() {
		return agentID;
	}
	

}

 

 

3. CustomerTest클래스 코드

package polymorphism;

public class CustomerTest {

	public static void main(String[] args) {
		Customer customerLee = new Customer();
		customerLee.setCustomerID(10010);
		customerLee.setCustomerName("이순신");
		customerLee.bonusPoint = 1000;
		
		System.out.println(customerLee.showCustomerInfo());
		
		Customer customerKim = new VIPCustomer(10020,"김유신",12345);
		customerKim.bonusPoint = 1000;
		
		System.out.println(customerKim.showCustomerInfo());
		System.out.println("==== 할인율과 보너스 포인트 게산 ====");
		
		int price = 10000;
		int leePrice = customerLee.calcPrice(price);
		int kimPrice = customerKim.calcPrice(price);
		
		System.out.println(customerLee.getCustomerName() + " 님이 " + leePrice + "원 지불하셨습니다.");
		System.out.println(customerLee.showCustomerInfo());
		
		System.out.println(customerKim.getCustomerName() + " 님이 " + kimPrice + "원 지불하셨습니다.");
		System.out.println(customerKim.showCustomerInfo());
	}
}

실행 결과 10000 원 가격의 상품을 구입 시 등급에 따라서 다른 할인율과 포인트 적립이 이뤄지고 있습니다. 그런데 중요한 점은 customerLee와 customerKim이 선언될 때 customer로 선언이 되었다는 점입니다. 때문에 자료형은 Customer로 동일하지만 할인율과 보너스와 관련된 메서드 적용에 대해서는 각 인스턴스의 메서드에 맞게끔 계산이 되었습니다.

즉 상속 관계에 있는 상위 클래스와 하위 클래스는 같은 상위 클래스 자료형으로 선언되어 생성할 수 있지만 재정의된 메서드는 각각 호출될 뿐만 아니라 이름이 같은 메서드가 서로 다른 역할을 구현하고 있음을 확인할 수 있습니다.

출처 : Do it, Introduction to Java Programming. 

반응형

댓글