본문 바로가기

프로그래밍 언어/JAVA

JAVA 입문 - 다형성 활용

지난 글: [프로그래밍 언어/JAVA] - JAVA 입문 - 다형성

 

앞서 배웠던 상속과 다형성을 활용하면 프로그램을 유지보수하는 데 굉장히 편리하다고 한다. 이 때 배열을 함께 사용하면 여러 하위 클래스 자료형을 상위 클래스 자료형으로 한꺼번에 관리할 수도 있다. 

 

일반 고객과 VIP 고객의 중간 등급 만들기

더보기

시나리오:

고객이 늘어 VIP 고객만큼 물건을 많이 구매하지는 않지만 그래도 단골인 분들에게 혜택을 주고 싶다. 하여 GOLD 고객 등급을 하나 추가한다. GOLD 고객의 혜택은 아래와 같다.

-제품을 살 때는 항상 10% 할인해준다.

-보너스 포인트를 2% 적립해준다.

-담당 전문 상담원은 없다.

============================================================================이처럼 새로운 고객 등급이 생겼다. 이 내용을 기반으로 Customer 클래스를 상속받는 GoldCustomer 클래스를 구현해보자.

 

GOLD 고객 구현하기

GoldCustomer 클래스는 지불 가격과 보너스 포인트를 계산하는 calcPrice( ) 메서드만 재정의했다. 

 

배열로 고객 5명 구현하기

시나리오:

이 회사의 고객은 현재 5명이다. VIP 1명, GOLD 2명, SILVER 2명이다. 이 고객들이 각각 10,000원짜리 상품을 구매했을 때의 결과를 출력한다.

============================================================================고객 인스턴스가 5개이므로 배열에 넣어서 관리하자. 객체 배열 ArrayList는 자료형을 선언해야 한다. 여기서 사용할 클래스는 Customer, GoldCustomer, VIPCustomer 세 종류이다. 배열 자료형을 Customer로 지정하고, VIPCustomer 클래스와 GoldCustomer 클래스 모두 Customer 클래스를 상속받은 클래스이므로 Customer형으로 선언한다. 이렇게 선언하면 이 배열에는 세 종류의 클래스 모두 사용 가능하다. 그리고 Customer 하위 클래스의 인스턴스가 추가될 때 모두 Custom er형으로 묵시적 형 변환이 이루어진다. 

 

배열을 활용한 고객 관리 프로그램 구현하기

출력 결과

for(Customer customer : customerList) 문장은 customerList 배열의 요소를 하나씩 가져와서 Customer형 변수에 넣는다. 고객 정보를 ArrayList 배열에 저장할 때 Customer형으로 형 변환을 하여 추가했기에 배열 요소를 하나씩 가져올 때도 Customer형으로 가져온다. 그리고 각 인스턴스가 calcPrice( ) 메서드를 호출하면 현재 이 변수의 실제 인스턴스가 무엇이냐에 따라 재정의한 메서드를 각각 호출하여 계산한다. 이것이 다형성이다.

 

만약 재정의한 메서드가 가상 메서드 방식에 의해 자동으로 호출되지 않는다면 if-else-if문을 사용하여 각 자료형에 맞는 코드를 따로 구현해야 한다. 게다가 새로운 등급의 고객이 추가로 필요한 경우 또 다른 조건을 구현해야 하므로 코드의 유지보수가 어려워진다. 이런 경우에 상속과 다형성을 잘 활용하여 코드를 간결하게 줄이고 확장성 있는 프로그램을 구현하는 것이다.

 

속의 사용 시기

더보기

VIPCustomer 클래스는 이미 구현된 Customer 클래스에서 몇 가지 추가 요구 사항만 생긴 것이다. 그렇다면 Customer 클래스에 VIP 고객의 내용도 함께 구현할 수 있을 것이다. 하지만 추가 기능을 이처럼 구현하면 코드가 굉장히 복잡해진다. 이유는 일반 고객은 사용하지 않는 속성인 VIP 고객만을 위한 서비스 내용을 추가해야하기 때문이다. 아래 코드는 Customer 클래스에 모든 등급의 내용을 넣어 구현한 예시다.

if(customerGrade == "VIP") {
}
else if(customerGrade == "GOLD") {
}
else if(customerGrade == "SILVER") {
}
더보기

고객 등급에 따라 다르게 구현해야 하기에 if-else-if-else문을 사용한다. 이는 등급에 따라 다른 구현이 필요한 모든 메서드에 적용된다. 이러면 고객의 등급이 하나라도 추가되거나 삭제되면 유지보수가 매우 복잡해진다.

 

위에서 얘기했듯 상속을 사용하면 모든 등급에서 공통으로 사용하는 코드 부분은 상위 클래스인 Customer 클래스에 구현하고 각 등급별 고객의 내용은 각각의 하위 클래스에 구현한다. 또 새로운 등급의 고객이 추가되어도 기존의 코드를 거의 수정하지 않고 새로운 클래스를 추가할 수 있다. 

 

상속을 항상 하는 것이 좋나?

이는 정답이 아니다. 'IS-A 관계(is a relationship; inheritance)'라는 용어가 있다. IS-A 관계란 일반적인 개념과 구체적인 개념의 관계로 '사람은 포유류이다'와 같은 관계인 것이다. 상속은 이 IS-A 관계에서 사용하는 것이 가장 효율적이다. 만약 단순히 코드를 재사용할 목적으로 서로 관련이 없는 개념의 클래스들을 상속 관계로 사용한다면 그것은 좋지 않은 코드 작성법이다. 상속을 사용하면 클래스 간의 결합도가 높아져 상위 클래스의 변화가 하위 클래스에 미치는 영향이 크다.

따라서 상속은 '일반적인 클래스'와 '구체적인(확장되는) 클래스'의 관계에서 구현하는 것이 맞다.

 

참고 서적: 자바 프로그래밍 입문 - 박은종