728x90
다형성이란?
- 지금까지 설명한 묵시적 클래스 형 변환과 가상 메서드를 바탕으로 객체 지향의 중요한 특성인 다형성(polymorphism) 을 학습해 봅시다.
- 다형성 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();
}
}
- AnimalTest1 클래스에 moveAnimal( ) 메서드를 만들었습니다.
- moveAnimal( ) 메서드는 Animal 자료형을 매개변수로 받아서 move( ) 메서드를 실행합니다.
- 여기서 중요한 것은 Animal 형이 상위 클래스입니다.
- 따라서 매개변수가 전달되는 부분에 Human 인스턴스가 전달되었다면 우리가 이전에 배웠던 것처럼 묵시적 클래스 형 변환이 일어납니다.
Animal ani = new Human( );
- Animal 에서 상속받은 클래스가 매개변수로 넘어오면 모두 Animal 형으로 변환되므로 animal.move( ) 메서드를 호출할 수 있습니다.
- move( ) 라는 메서드는 하위 클래스에서 재정의된 함수이므로 가상 함수 원리에 따라서 Animal 의 move 가 아닌 실제 인스턴스의 메서드의 move( ) 메서드가 실행됩니다.
- animal.move( ) 라는 코드는 변함이 없지만 어떤 매개변수가 넘어왔느냐에 따라 출력문이 달라집니다. 이것이 바로 다형성 polymorphism 입니다.
다형성의 장점
- 위의 예시에서 다른 동물이 새로 추가되는 경우를 생각해 보겠습니다.
- 새로운 동물도 Animal 클래스를 상속받아 구현하면 모든 클래스를 Animal 자료형 하나로 쉽게 관리할 수 있습니다.
- 이것이 다형성을 활용한 프로그램의 확장성입니다.
- 만약 다형성이 없었다면 각 자료형에 따라 코드를 다르게 구현했을 것이고, 코드는 훨씬 복잡해지고 내용도 길어졌을 겁니다.
- 상위 클래스에서 공통 부분의 메서드를 제공하고, 하위 클래스에서는 그에 기반한 추가 요소를 덧붙여 구현하면 코드 양도 줄어들고 유지보수도 편리합니다.
- 또 필요에 따라 상속받은 모든 클래스를 하나의 상위 클래스로 처리할 수 있고 다형성에 의해 각 클래스의 여러 가지 구현을 실행할 수 있으므로 프로그램을 쉽게 확장할 수 있습니다.
- 이처럼 다형성을 잘 활용하면 유연하면서도 구조화된 코드를 구현하여 확장성 있고 유지보수 하기 좋은 프로그램을 개발할 수 있습니다.
다형성을 활용해 VIP 고객 클래스 완성하기
- 앞선 예제에서 살펴보았던 VIP 고객의 혜택을 다형성으로 구현해 보겠습니다.
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 + "입니다.";
}
}
- 위 코드에서 기존 코드와 달라진 점은 initCustomer( ) 메서드가 생성되었다는 점입니다.
- 이 메서드는 클래스의 멤버 변수를 초기화 하는데, Customer 클래스의 생성자 2개 모두에서 사용되는 부분이므로 메서드로 분리하여 호출하였습니다.
- 이번에는 VIP 고객 클래스를 수정하겠습니다.
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;
}
}
- VIP 고객 클래스에서 calcPrice( ) 메서드와 showCustomerInfo( ) 메서드를 재정의했습니다.
- 일반 고객 클래스에서 calcPrice( ) 메서드는 정가를 그대로 반환했지만, VIP 고객 클래스에서는 할인율을 반영한 지불 가격을 반환합니다.
- 또한 VIP 고객 클래스의 정보를 출력할 때는 Customer 클래스에서 출력한 정보에 더해서 담당 상담원 번호까지 출력합니다.
public class CustomerTest {
public static void main(String[] args) {
Customer customerLee = new Customer(10010, "이순신");
Customer customerKim = new VIPCustomer(10020, "김유신", 12345);
customerLee.bonusPoint = 1000;
customerKim.bonusPoint = 1000;
System.out.println(showCustomerInfo(customerKim));
System.out.println(customerKim.showCustomerInfo());
System.out.println(showCustomerInfo(customerLee));
System.out.println(customerLee.showCustomerInfo());
System.out.println(customerKim.customerName + "님이 " + calcPrice(customerKim, 10000) + "원 지불하셨습니다.");
System.out.println(customerKim.customerName + "님이 " + customerKim.calcPrice(10000) + "원 지불하셨습니다.");
System.out.println(customerLee.customerName + "님이 " + calcPrice(customerLee, 10000) + "원 지불하셨습니다.");
System.out.println(customerLee.customerName + "님이 " + customerLee.calcPrice(10000) + "원 지불하셨습니다.");
}
public static String showCustomerInfo(Customer customer) {
return customer.showCustomerInfo();
}
public static int calcPrice(Customer customer, int price) {
return customer.calcPrice(price);
}
}
- 위의 코드에서는 다형성을 2가지 방법으로 접근하여 사용했습니다.
- 여기서 중요한 것은 customerLee 와 customerKim 은 모두 Customer 형으로 선언되었지만, 할인율과 보너스 포인트는 각 인스턴스의 메서드에 맞게 가상 메서드가 작동하였다는 것입니다.
- 즉 상속 관계에 있는 상위 클래스와 하위 클래스는 같은 사우이 클래스 자료형으로 선언되어 생성할 수 있지만 재정의된 메서드는 각가 호출될 뿐만 아니라 같은 이름의 메서드가 서로 다른 역할을 구현할 수 있습니다.
'[그린컴퓨터] Server > JAVA(객체 지향 프로그래밍)' 카테고리의 다른 글
다운 캐스팅과 instanceof { 다운 캐스팅이란, instanceof란 } (0) | 2023.05.31 |
---|---|
다형성 활용하기 { 배열과 다형성, 배열과 다형성 활용하기, 상속은 언제 사용할까 } (0) | 2023.05.31 |
메서드 오버라이딩 { 상위 클래스 메서드 재정의하기, VIP 고객 클래스의 제품 가격 계산 메서드 재정의하기, 묵시적 클래스 형 변환과 메서드 재정의, 가상 메서드 } (0) | 2023.05.30 |
상속에서 클래스 생성과 형 변환 { 하위 클래스가 생성되는 과정, 부모를 부르는 예약어 super, 상위 클래스로 묵시적 클래스 형 변환 } (0) | 2023.05.29 |
상속이란 { 상속이란, 클래스의 상속, 상속을 사용하여 고객 관리 프로그램 구현하기 } (0) | 2023.05.29 |