JAVA Basic) 다형성
Programming/Java 기초

JAVA Basic) 다형성

728x90

 

목차

     


     

    <다형성이란?>

    묵시적 클래스 형 변환과, 가상메서드를 바탕으로 객체 지향의 중요한 특성인 '다형성(polymophism)'을 알아보자.
    '다형성'이란, 하나의 코드가 여러 자료형으로 구현되어 실행되는 것이다.
    쉽게 말하면, 같은 코드에서 여러가지 실행 결과가 나오는 것이다.

    객체 지향 언어의 다형성

    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();	//재정의된 메서드가 호출됨.
    	}
    }

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

    Animal ani = new Human();

    Animal에서 상속받은 클래스가 매개변수로 넘어오면 모두 Animal형으로 변환되므로, animal.move()메서드를 호출할 수 있다.
    가상 메서드의 원리에 따라 animal.move()메서드가 호출하는 메서드는 Animal클래스의 move()메서드가 아닌, 매개변수로 넘어온 실제 인스턴스의 메서드가 호출된다.
    animal.move() 코드는 변함이 없지만 어떤 매개변수가 넘어왔느냐에 따라 출력문이 달라진다.

    이것이 바로 '다형성'이다.

     

     

    다형성의 장점

    여기에 다른 동물들이 추가되는 경우를 보자.
    새로운 동물도 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() { //멤버 변수의 초기화 부분
    		customerGrade = "SILVER";
    		bonusRatio = 0.01;
    	}
    	
    	public int calcPrice(int price) {
    		bonusPoint += price * bonusRatio;
    		return price;
    	}
    	public String showCustomerInfo() {
    		return customerName + "님의 등급은 " + customerGrade + "이며, 보너스 포인트는 " + bonusPoint + "입니다.";
    	}
        ...

    기존 Customer 클래스와 달라진 점을 보자면, initCustomer()메서드가 생겼다.
    이 메서드는 클래스의 멤버 변수를 초기화하는데, Customer 클래스를 생성하는 두 생성자에서 공통으로 사용하는 코드이므로 메서드로 분리하여 호출.

    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클래스에서는 할인율을 반영한 지불가격을 반환한다.
    또 일반 고객 클래스에서 showCustomerInfo()메서드는 고객 등급과 이름만 출력했지만, VIP고객 클래스에서는 상담원 번호까지 출력한다.

    Test클래스

    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);
    		//VIPCustomer를 Customer형으로 선언
    		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());
    	}
    }

    출력 결과를 보면 10,000원짜리 상품을 구입했을 때 등급에 따라 다른 할인율과 포인트 적립이 이루어지는 것을 알 수 있다.

    그런데 여기에서 customerLee와 customerKim은 모두 Customer형으로 선언되었고, 고객의 자료형은 Customer형으로 동일하지만 할인율과 보너스 포인트는 각 인스턴스의 메서드에 맞게 계산되었다.
    상속 관계에 있는 상위 클래스와 하위 클래스는 같은 상위 클래스 자료형으로 선언되어 생성할 수 있지만 재정의된 메서드는 각각 호출될 뿐만 아니라 이름이 같은 메서드가 서로 다른 역할을 구현하고 있음을 알 수 있다.


    [Do it! 자바 프로그래밍 입문] 도서로 공부하며 정리한 글입니다.

    300x250