본문 바로가기
프로그래밍 ( Programming )/JAVA

[JAVA] 상속이란?

by Jayce_choi 2021. 6. 26.
반응형

객체 지향 프로그래밍에서 중요한 특징 중 하나로 상속이라는 개념이 있습니다. 상속은 단어 자체로 무엇인가를 물려받는다는 의미를 지녔습니다.

예를 들어서 부모가 자식에게 물려주는 재산을 상속이라고 할 때 부모에게 재산을 받으면 상속받은 재산을 자신의 것으로 사용이 가능해집니다. 즉 객체 지향 프로그램에서도 마찬가지입니다. 즉 B 클래스가 A 클래스로 부터 상속을 받게 되면 B 클래스는 A의 클래스 멤버 변수와 메서드를 사용 가능해집니다. 객체 지향 프로그램은 유지 보수하기 편하고 프로그램을 수정하거나 새로운 내용을 추가하는 것이 유연한데, 그 기반이 되는 기술이 바로 상속이기 때문입니다.  

클래스의 상속

상속을 그림으로 표현할때는 다음과 같이 표현합니다.

보통은 화살표를 보고 B 클래스가 A 클래스에게 상속을 넘긴다라고 표현한다고 파악을 할 수 있으나 실제는 상속받는 클래스에서 상속하는 클래스로 화살표가 가므로 헷갈리면 안 됩니다.

( 때문에 부모 클래스 (Parent Class)는 A 클래스가 되며 또한 자식 클래스는 (Child Class) B 클래스가 됩니다. ) 

 

클래스의 상속 문법

자바 문법으로 상속을 구현할 때는 extends 예약어를 사용합니다. 이때 사용되는 extends 예약어는 '연장, 확장하다'라는 의미를 지니며 즉 A가 가지고 있는 속성이나 기능을 추가로 확장하여 B 클래스를 구현한다는 뜻을 가지고 있습니다.  하단의 간단한 코드는 B 클래스가 A 클래스를 상속받는다라고 말하고 있습니다.

class B extends A {
}

하나의 예시를 더 보겠습니다. 사람은 기본적으로 동물입니다. 그리고 그중에서도 포유류에 속합니다. 때문에 다음과 같은 화살표 관계로 표현이 가능하며 일반적인 개념은 포유류가 되며 그 포유 류안에서 더 구체적인 클래스를 보여주는 것이 사람 클래스라고 생각하면 되겠습니다.

 

예제 ) 상속을 사용하여 고객 관리 프로그램을 구현해보자.

회사에서 고객 정보를 가지고 맞춤 서비스를 제공하기 위해서 고객 관리 프로그램이 필요합니다. 구현을 위해서는 고객 클래스가 있어야 하며 고객 클래스를 구현하기 위해서는 클래스 속성을 멤버 변수로 선언을 해야 합니다.

기본적인 설정은 고객(Customer) 클래스의 구성은 다음과 같습니다.

Customer 클래스

package inheritance;

public class Customer {
	private int customerID;
	private String customerName;
	private String customerGrade;
	int bonusPoint;
	double bonusRatio;
	
	public Customer() {
		customerGrade = "SILVER";
		bonusRatio = 0.01;
	} // 디폴트 생성자
	
	public int calcPrice(int price) {
		bonusPoint += price * bonusRatio;
		return price;
	} // 보너스 포인트 적립, 지불 가격 계산 메서드 
	
	public String getCustomerInfo() {
		return customerName = "님의 등급은 " + customerGrade + "이며, 보너스 포인트는" + bonusPoint + "입니다.";
	} // 고객 정보를 반환하는 메서드
}

위의 코드는 기존의 클래스 구현과 관련된 코드와 특별하게 다른 점이 없습니다. 때문에 다음 상황을 생각해보겠습니다.

 

예제 시나리오 - 새로운 고객 등급이 필요한 경우

: 고객이 점점 늘어나고 판매도 많아지다 보니 단골 고객이 생겼습니다. 단골 고객은 회사 매출에 많은 기여를 하는 우수 고객입니다. 이 우수 고객에게 좋은 혜택을 주고 싶습니다. 우수 고객 등급은 VIP이고, 다음과 같은 혜택을 제공합니다.

  • 제품을 살 때는 항상 10% 할인
  • 보너스 포인트를 5% 적립
  • 담당 전문 상담원을 배정해 줌.

즉 해당 시나리오에서 설명하는 이야기는 이미 Customer 클래스가 존재하는데 VIP를 위해서 필요한 변수와 메서드를 만들어야 합니다. 하지만 기존의 방법대로 한다면 Customer에서 사용된 메서드들이 동일하게 VIPCustomer 클래스를 구현할 때 다시 작성을 해줘야 하는 번거로움이 생깁니다. 때문에 상속 방법을 이용하여 다음과 같이 작성할 수 있습니다.

package inheritance;

public class VIPCustomer extends Customer {
	private int agentID;
	double saleRatio;
	
	public VIPCustomer() {
		customerGrade = "VIP";
		bonusRatio = 0.05;
		saleRatio = 0.1;
	}
	public int getAgentID() {
		return agentID;
	}	
}

그러나 해당 코드와 같이 구성하게 되면 2가지 문제점이 발생합니다.

첫 번째 문제점은 Customer(상위 클래스)에서 customerGrade는 private로 선언되어있기 때문에 외부 클래스에서는 사용이 불가능합니다.

두 번째 문제점은 VIP 고객에게 제공하는 혜택인 할인율과 세일 가격을 어떻게 적용시킬지에 대한 구체적인 방안이 없습니다. ( 해당 문제는 메서드 오버 라이딩 파트에서 구체적으로 설명을 하겠습니다. ) 

 

우선 첫 번째 문제점을 해결하기 위해서 상위 클래스에서의 변수를 상속을 받은 클래스에서 사용하기 위해 protected 예약어를 사용합니다.

protected 예약어는 상위클래스에서 작성한 변수나 메서드를 외부 클래스에서 사용이 가능하도록 해주는 예약어입니다. 즉 상속받은 하위 클래서에서는 public처럼 사용이 가능해집니다. protected는 상속된 하위 클래스를 제외한 나머지 외부 클래스에서는 private와 동일한 역할을 수행합니다.

protected 명령어를 이용하여 Customer 클래스에 있는 private 변수를 다른 하위 클래스의 위치에서도 사용이 가능하도록 바꿔봅시다.

package inheritance;

public class Customer {
	protected int customerID;
	protected String customerName;
	protected String customerGrade;
	int bonusPoint;
	double bonusRatio;
	
	public Customer() {
		customerGrade = "SILVER";
		bonusRatio = 0.01;
	} // 디폴트 생성자
	
	public int calcPrice(int price) {
		bonusPoint += price * bonusRatio;
		return price;
	} // 보너스 포인트 적립, 지불 가격 계산 메서드 
	
	public String getCustomerInfo() {
		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;
	}
	
}

여기서 추가된 코드는 protected로 선언한 customerID, customerName, customerGrade 변수를 사용하기 위해서 get()과 set () 메서드를 추가하였습니다.

protected 예약어로 선언된 변수는 외부 클래스에는 private 변수처럼 get() 메서드를 사용하여 값을 가져올 수 있으며 set() 메서드를 통해서 값을 지정이 가능합니다. Customer 클래스를 상속받은 VIPCustomer 클래스는 protected로 선언한 변수를 상속받게 되고 나머지 public 메서드도 상속받아서 사용이 가능해집니다. (이제 VIPCustomer 부분의 오류는 사라지게 됩니다.)

이제 만들어진 클래스를 테스트해보기 위해서 main문을 작성합니다.

package inheritance;

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.getCustomerInfo());
		
		VIPCustomer customerKim = new VIPCustomer();
		customerKim.setCustomerID(10020);
		customerKim.setCustomerName("김유신");
		customerKim.bonusPoint = 10000;
		System.out.println(customerKim.getCustomerInfo());
	}

}

이를 통해서 Customer 클래스를 customerLee 참조 변수에 대입하고

VIPCustomer 클래스를 customerKim 변수에 대입하였습니다. 결과적으로 VIPCustomer가 Customer를 상속했기에 고객 아이디 고객 이름의 메서드를 사용할 수 있게 되었습니다.

 

출처: Do it, Introduction to Java Programming. 

반응형

'프로그래밍 ( Programming ) > JAVA' 카테고리의 다른 글

[JAVA] 상속에서 클래스 생성과 형 변환  (0) 2021.06.26
[JAVA] ArrayList 란  (0) 2021.06.10
[JAVA] 배열  (0) 2021.06.01
[JAVA] static 응용 - 싱글톤 패턴  (0) 2021.05.28

댓글