Part2. 3-6 다형성과 다형성을 사용하는 이유
* 다형성(polymorphism)이란
하나의 코드가 형변환(업캐스팅)을 통해서 여러 자료형으로 구현되어 실행되는 것
같은 코드에서 여러 다른 실행 결과가 나옴
정보은닉, 상속과 더불어 객체지향 프로그래밍의 가장 큰 특징 중 하나임
다형성을 잘 활용하면 유연하고 확장성있고, 유지보수가 편리한 프로그램을 만들수 있음
원래는 Java 파일 하나에 클래스 하나를 많이 만드는데 클래스가 여러 개 들어갈 수 도 있다
Java 파일 하나에 public 클래스는 한 개이다
moveAnimal() 메서드의 매개변수의 자료형은 Animal 이고, 들어가는 객체들의 자료형은 하위 클래스인 human, tiger, eagle 이어서 자동으로 형변환이 된다
코드는 한 줄인데 어떤 데이터 형이 들어갔느냐에 따라, 어떤 인스턴스 형이 들어갔느냐에 따라
movAnimal 메서드의 implementation (실행) 이 달라진다 --> 이게 바로 다형성
상속을 하게 되면 하위 클래스들을 상위 클래스 하나의 타입으로 모두 핸들링할 수 가 있다
이런 것을 클래스 간의 결합도가 굉장히 타이트해진다고 말한다
moveAnimal() 메서드의 매개변수인 animal 변수는 자료형이 Animal 클래스이기 때문에
하위 클래스인 human 클래스의 readBook() 메서드나 tiger 클래스의 hunting() 메서드는 호출할 수 없다
호출하고 싶으면 다운 캐스팅을 해야 한다. (다운 캐스팅은 이후 강의에서)
class Animal{ // 상위 클래스 Animal
public void move() {
System.out.println("동물이 움직입니다.");
}
public void eating() {
}
}
class Human extends Animal{ // 하위 클래스 1 Human
public void move() {
System.out.println("사람이 두발로 걷습니다.");
}
public void readBooks() {
System.out.println("사람이 책을 읽습니다.");
}
}
class Tiger extends Animal{ // 하위 클래스 2 Tiger
public void move() {
System.out.println("호랑이가 네 발로 뜁니다.");
}
public void hunting() {
System.out.println("호랑이가 사냥을 합니다.");
}
}
class Eagle extends Animal{ // 하위 클래스 3 Eagle
public void move() {
System.out.println("독수리가 하늘을 날아갑니다.");
}
public void flying() {
System.out.println("독수리가 날개를 쭉 펴고 멀리 날아갑니다");
}
}
public class AnimalTest { // public 클래스는 Java파일에 1개 있어야 한다
public static void main(String[] args) {
Animal hAnimal = new Human(); // 형변환
Animal tAnimal = new Tiger(); // 자료형은 Animal이지만 생성자는 하위 클래스 생성자
Animal eAnimal = new Eagle();
AnimalTest test = new AnimalTest();
test.moveAnimal(hAnimal);
test.moveAnimal(tAnimal);
test.moveAnimal(eAnimal);
// 객체 배열을 위해 만들어진 ArrayList 활용
ArrayList<Animal> animalList = new ArrayList<Animal>();
animalList.add(hAnimal);
animalList.add(tAnimal);
animalList.add(eAnimal);
for(Animal animal : animalList) { // 향상된 for문
animal.move(); // 다형성 : 같은 코드에서 여러 다른 실행 결과가 나온다
}
}
public void moveAnimal(Animal animal) {
animal.move();
}
}
* 다형성을 사용하는 이유
상속과 메서드 재정의를 활용하여 확장성 있는 프로그램을 만들 수 있다
그렇지 않는 경우 메서드마다 많은 if-else if문이 구현되고 코드의 유지보수가 어려워짐
상위 클래스에서는 공통적인 부분을 제공하고 하위 클래스에서는 각 클래스에 맞는 기능 구현
여러 클래스를 하나의 타입(상위 클래스)으로 핸들링 할 수 있음
상속을 할 때 상속의 깊이를 너무 깊게 하는 것은 좋지 않다.
ArrayList 는 넣은 순서대로 출력이 된다
public class GoldCustomer extends Customer{ // Gold 등급 추가
double saleRatio;
public GoldCustomer(int customerID, String customerName){
super(customerID, customerName);
customerGrade = "GOLD";
bonusRatio = 0.02; // Gold 등급은 2%
saleRatio = 0.1;
}
public int calcPrice(int price){
bonusPoint += price * bonusRatio; // Gold 등급의 비율은 2%
return price - (int)(price * saleRatio);
}
}
public class CustomerTest {
public static void main(String[] args) {
ArrayList<Customer> customerList = new ArrayList<Customer>();
Customer customerLee = new Customer(10010, "이순신"); // 형변환(업캐스팅)
Customer customerShin = new Customer(10020, "신사임당");
Customer customerHong = new GoldCustomer(10030, "홍길동");
Customer customerYul = new GoldCustomer(10040, "이율곡");
Customer customerKim = new VIPCustomer(10050, "김유신", 12345);
customerList.add(customerLee); // ArrayList 에 추가
customerList.add(customerShin);
customerList.add(customerHong);
customerList.add(customerYul);
customerList.add(customerKim);
System.out.println("====== 고객 정보 출력 =======");
for( Customer customer : customerList){ // 향상된 for문
System.out.println(customer.showCustomerInfo());
}
System.out.println("====== 할인율과 보너스 포인트 계산 =======");
int price = 10000;
for( Customer customer : customerList){
int cost = customer.calcPrice(price); // calcprice 메서드 사용
System.out.println(customer.getCustomerName() +" 님이 " + + cost + "원 지불하셨습니다.");
System.out.println(customer.getCustomerName() +" 님의 현재 보너스 포인트는 " + customer.bonusPoint + "점입니다.");
}
}
}