모든지 기록하자!

[Java] 상속 (예제 : 고객관리) 본문

Java

[Java] 상속 (예제 : 고객관리)

홍크 2021. 5. 14. 22:14
728x90

상속(inheritance)이란?

객체 지향 프로그래밍의 중요한 특징 중 하나가 상속(inheritance)이다.

객체 지향 프로그램은 유지, 보수가 편하고 프로그램을 수정하거나 새로운 내용을 

추가하는 것이 유연한데 그 기반이 되는 기술이 바로 상속이다.

 

 

부모에게 재산을 상속받으면 상속받은 재산을 자신의 것으로 사용할 수 있다.

객체 지향 프로그램에서도 B클래스가 A클래스를 상속받으면 B클래스는 

A클래스의 멤버 변수와 메서드를 사용할 수 있다.

 

클래스 상속 문법

자바 문법으로 상속을 구현할 때는 extends 예약어를 사용한다.

이때 사용하는 extends는 '연장' , '확장하다'의 의미이다.

 

 is ~ a관계(상속) : 큰 개념에서 작은 개념으로 구체화되는 관계 ex) 동물 -> 포유류 -> 양
  
  1. 단일 상속을 원칙으로 한다. (다중 상속 x)
  2. 상속해주는 클래스 : super class
     상속 받는 클래스 : sub class
  3. super class는 sub class의 공통된 부분을 제공함으로써
     중복된 코드를 발생하지 않고, 확장성이 좋아진다.
  4. extends 상속받은 클래스명 
  5. 모든 클래스는 Object class를 상속받고 있다.

 

 

상속을 사용하여 고객 관리 프로그램 구현하기

public class Customer {
	
	private int customerID; // 고객 아이디
	private String customerName; // 고객 이름
	private String customerGrade; // 고객 등급
	int bonusPoint; // 보너스 포인트
	private double bonusRatio; // 포인트 적립 비율
	
	public Customer() {
		customerGrade = "SILVER"; // 기본등급은 실버
		bonusRatio = 0.01; // 보너스 포인트의 기본 적립 비율
	}

	public int calcPrice(int price){		
		                                  // 실버등급의 보너스 포인트 계산
		bonusPoint += price * bonusRatio; // 구매금액 * 0.01 (1% 적립)		
		return price;
	}
	
	public String showCustomerInfo(){
		return customerName + "님의 등급은 " + customerGrade + "이고, 
        			보너스 포인트는 " + bonusPoint + "점 입니다.";  
	}
 }
	
	

모든 멤버 변수를 private로 선언할 필요는 없다. 필요에 따라 멤버 변수나 메서드를 

외부에 노출하지 않을 목적일 때 private로 선언한다.

 

 

새로운 고객 등급이 필요한 경우

우수고객 등급은 VIP이고 

- 제품 구매 시 항상 10% 할인

- 보너스 포인트 5%

- 담당 전문 상담원 배정

 

해당 요구사항 들을 어떻게 구현해야 할까?

간단하게 이미 Customer 클래스에 VIP 고객에게 필요한 변수와 메서드까지

함께 포함하여 구현하는 것이다. 하지만 이렇게 구현하면 Customer 클래스의

코드가 복잡해진다. 그리고 일반 고객의 인스턴스를 생성할 때는 VIP 고객과

관련된 기능은 전혀 필요 없는데 VIP 고객의 내용까지 같이 생상 되어 낭비가 발생한다.

그렇기 때문에 VIPCustomer 클래스를 따로 구현하는 것이 좋다.

VIP 고객 클래스 생성

public class VIPCustomer {
	
	private int customerID;
	private String customerName;
	private String customerGrade;  // Cutomer 클래스와 겹치는 맴버 변수들
	int bonusPoint;
	private double bonusRatio;
    
    private int agentID; // VIP고객 담당 상담원 아이디
    double saleRatio; // 할인율
	
	public VIPCustomer() {
		customerGrade = "VIP"; // VIP등급고객
		bonusRatio = 0.05; // 보너스 적립 5%
        saleRatio = 0.1; // 할인율 10%    
	}	
 		
	public int calcPrice(int price){
				
		bonusPoint += price * bonusRatio;		
		return price-(int)(price * saleRatio); // 할인율 적용
	}
    
    public int getAgentID() { // VIP 고객에게만 필요한 메서드
    	return agentID;
    }
	
	public String showCustomerInfo(){
		return customerName + "님의 등급은 " + customerGrade + "이고, 
       				 보너스 포인트는 " + bonusPoint + "점 입니다.";  
	}

클래스를 만들고 보니 앞에서 만든 Coutomer 클래스와 겹치는 멤버 변수와 메서드가 많다.

calcPrice() 메서드는 이름은 같은데 구현 내용은 다르다. 일반 고객에게 제공하는 혜택을

기본으로 제공하고 추가 속성과 메서드가 있는 것이다. 이런 경우에 상속을 사용한다.

Customer 클래스에 일반 고객의 속성과 기능이 이미 구현되어 있기 때문에

VIPCustomer 클래스는 Customer 클래스를 상속받고 VIP 고객에게 필요한 추가 속성과 

기능을 구현하는 것이다. 

 

Customer 클래스를 상속한 VIPCustomer 클래스

public class VIPCustomer extends Customer{ // VIPCustomer클래스는
					 // Customer클래스를 상속받음
	private int agentID;
	private double saleRatio;

	public VIPCustomer() {
   	customerGrade = "VIP"; // 상위 클래스에서 private 변수이므로 
     	bonusRatio = 0.05;     // 오류가 발생
     	saleRatio = 0.1;
    }
    
    public int getAgentID(){
    	return agentID;
    }
}

VIPCustomer 클래스의 코드가 간단해졌다.

 

 

해당 메서드들은 상속을 받아서 사용할 것이기 때문에 구현하지 않았다.

	private String customerName;
	private String customerGrade;  // Cutomer 클래스와 겹치는 맴버 변수들
	int bonusPoint;
	private double bonusRatio;
    
    	public String showCustomerInfo(){
		return customerName + "님의 등급은 " + customerGrade + "이고, 
       				 보너스 포인트는 " + bonusPoint + "점 입니다.";  
	}

 

위 코드에는 두 가지 문제가 있다. 

첫 번째 private String customerGrade; // private 클래스는 외부에서 사용할 수 없다.

두 번째 VIP 고객에게 제공하는 혜택인 할인율과 세일 가격을 어떻게 적용할지 구현하지 않았다.

 

 

상위 클래스 변수를 사용하기 위한 protected

상위 클래스에 작성한 변수나 메서드 중 외부 클래스에서 사용할 수 없지만 하위 클래스에서는 

사용할 수 있도록 지정하는 예약어가 protected이다. 상속받은 하위 클래스에서는 public처럼 

사용할 수 있다. protected는 상속된 하위 클래스를 제외한 나머지 외부 클래스에서는 private와 동일

 

 

protected 선언 get(), set() 메서드 추가

public class Customer {
	
	protected int customerID;
	protected String customerName;
	protected String customerGrade;
	int bonusPoint;
	protected double bonusRatio;
	
	public Customer() {
		customerGrade = "SILVER";
		bonusRatio = 0.01;
		
	}
	
	public Customer(int customerID, String customerName){
		this.customerID = customerID;
		this.customerName = customerName;
		customerGrade = "SILVER";
		bonusRatio = 0.01;
	
	}
	
	public int calcPrice(int price){
		
		bonusPoint += price * bonusRatio;		
		return price;
	}
	
	public String showCustomerInfo(){
		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로 선언한 변수를 외부에서 사용할 수 있도록 get , set 메서드를 추가했다.

 

 

테스트 프로그램 실행하기

public class CustomerTest1 {

	public static void main(String[] args) {

		Customer customerLee = new Customer();
		customerLee.setCustomerID(10100);  // customerID와 Name은 
		customerLee.setCustomerName("이병헌"); // protected 변수이므로 set() 메서드 호출
		customerLee.bonusPoint = 1000;
		System.out.println(customerLee.showCustomerInfo());
		
		VIPCustomer customerChoi = new VIPCustomer();
		customerChoi.setCustomerID(10101);  // customerID와 Name은 
		customerChoi.setCustomerName("최민식"); // protected 변수이므로 set() 메서드 호출
		customerChoi.bonusPoint = 1000;		
		System.out.println(customerChoi.showCustomerInfo());
	}
}

 

 

출력 결과

 

 

이후에 생성자, super, 클래스 형 변환 , 오버 라이딩을 사용해 변경해보자

 

728x90
Comments