코린이의 소소한 공부노트

다형성의 장점 본문

Java

다형성의 장점

무지맘 2022. 5. 4. 23:47

지금까지 다형성에 대해 공부한 것은 다음과 같다.

1. 조상 타입의 참조변수에 자손 타입의 객체를 선언할 수 있다.

class Parent { }
class Child extends Parent { }

Parent p = new Child();

2. 참조변수의 형변환: 사용 가능한 멤버 개수 조절

class Parent { } // 멤버 3개
class Child extends Parent { } // 멤버 2개 + 상속 3개 = 총 5개

Parent p = new Child(); // p로 접근 가능한 멤버는 5개 중 3개

Child c = (Child)p; // c로 접근 가능한 멤버는 5개 중 5개

3. instanceof 연산자: 형변환 가능 여부 확인

class Parent { }
class Child1 extends Parent { }
class Child2 extends Parent { }

Parent p = new Parent();
Child1 c1 = new Child1();
Child2 c2 = new Child2();

// 조상-자손 관계에서 객체 타입 <= 클래스 타입일 때 true
System.out.println(p instanceof Parent); // true
System.out.println(c1 instanceof Parent); // true
System.out.println(c1 instanceof Child1); // true
System.out.println(c2 instanceof Parent); // true
System.out.println(c2 instanceof Child2); // true

// 조상-자손 관계에서 객체 타입 > 클래스 타입일 때 false
System.out.println(p instanceof Child1); // false
System.out.println(p instanceof Child2); // false

// 조상-자손 관계가 아닐 때 error
System.out.println(c1 instanceof Child2); // error
System.out.println(c2 instanceof Child1); // error

 

[다형성의 장점]

다형성의 장점은 2가지로 정리할 수 있다. 이를 설명하기 위해 다음 코드를 기본 틀로 사용할 예정이다. Product 클래스에는 멤버 변수가 2개 있고, 이를 상속받은 클래스 3개가 있다. Product를 구매하려는 Buyer 클래스에도 멤버 변수가 2개 있다.

class Product{		// 제품
    int price;		// 제품 가격
    int bonusPoint;	// 적립 포인트
}

class Tv extends Product { }
class Computer extends Product { }
class Audio extends Product { }

class Buyer {		// 구매자
    int money = 1000;	// 소지금액
    int bonusPoint = 0;	// 소유 포인트
}

1. 다형적 매개변수: 참조형 매개변수는 메서드 호출 시 자신과 같은 타입 또는 자손 타입의 인스턴스를 넘겨줄 수 있다.

이 상태에서 Buyer 클래스에 각 물건을 사는 buy라는 메서드를 만들고 싶다. 다형성을 이용하지 않는다면 아래와 같이 오버로딩을 이용해야 한다.

// Buyer 클래스 내부
void buy (Tv t){
    money -= t.price;
    bonusPoint += t.bonusPoint;
}

void buy (Computer c){
    money -= c.price;
    bonusPoint += c.bonusPoint;
}

void buy (Audio a){
    money -= a.price;
    bonusPoint += a.bonusPoint;
}

// 메인 내부
Buyer b = new Buyer();
Tv t = new Tv();
Computer c = new Computer();
Audio a = new Audio();

b.buy(t);
b.buy(c);
b.buy(a);

너무나도 불편한 일이다. 새 물건 클래스가 생기면 buy 메서드를 또 추가해야 한다. 하지만 우린 다형성을 배웠기 때문에 더 이상 이렇게 하지 않아도 된다.

// Buyer 클래스 내부
void buy (Product p){
    money -= p.price;
    bonusPoint += p.bonusPoint;
}

// 메인 내부
Buyer b = new Buyer();
Product p1 = new Tv();
Product p2 = new Computer();
Product p3 = new Audio();

b.buy(p1);
b.buy(p2);
b.buy(p3);

다형성으로 인해 조상 타입의 참조변수가 자손 타입의 객체를 가리킬 수 있기 때문에 위와 같이 buy 메서드를 간단하게 만들 수 있게 되는 것이다. 물건 클래스가 또 생겨도 buy 메서드를 추가할 필요가 없다.

위 코드를 좀 더 정리해서 실제로 사용해보면 아래와 같다. 다소 기니 천천히 읽어보자.

class Product{		// 제품
    int price;		// 제품 가격
    int bonusPoint;	// 적립 포인트
    Product(int price) { // 생성자
        this.price = price;
        bonusPoint = (int)(price/10.0);	// 포인트 = 제품가격의 10%
    }
}

class Tv extends Product {
    Tv() {		// 조상클래스의 생성자 Product(int price)를 호출
        super(100);	// Tv는 100만원
    }
    // Object클래스의 toString() 오버라이딩
    public String toString() { return "Tv"; }
}

class Computer extends Product {
    Computer() {
        super(200);	// Computer는 200만원
    }
    public String toString() { return "Computer"; }
}

class Audio extends Product {
    Audio() {
        super(50);	// Audio는 50만원
    }
	public String toString() { return "Audio"; }
}

class Buyer {		// 구매자
    int money = 1000;	// 소지금액
    int bonusPoint = 0;	// 소유 포인트
    void buy (Product p){
        if(money < p.price) {
            System.out.println("잔액이 부족합니다.");
            return;
        }
        money -= p.price;
        bonusPoint += p.bonusPoint;
        System.out.println(p + "을/를 구입하셨습니다.");
        // System.out.println(p.toString() + "을/를 구입하셨습니다."); // 과 같음
    }
}

// 메인 내부
Buyer b = new Buyer();
// 현재 1000만원, 적립 포인트 0점

b.buy(new Tv());	// 이렇게 사용하면 메인에서는 Tv나 Computer 객체에 접근할 수 없지만
// "Tv을/를 구입하셨습니다."
b.buy(new Computer()); // 메서드에서는 접근 가능
// "Computer을/를 구입하셨습니다."
System.out.println("현재 남은 돈은 " + b.money + "만원입니다.");
// "현재 남은 돈은 700만원입니다."
System.out.println("현재 보너스점수는 " + b.bonusPoint + "점입니다.");
// "현재 보너스점수는 30점입니다."

2. 하나의 배열로 여려 종류의 객체 다루기: 조상 타입의 배열에 자손 타입의 객체를 담을 수 있다.

위의 코드에서 보면 Product 타입의 참조 변수에 자손 객체를 담는 코드가 있었다.

Product p1 = new Tv();
Product p2 = new Computer();
Product p3 = new Audio();

이것을 배열로 표현하면 다음과 같다.

Product p[] = new Product[3];
p[0] = new Tv();
p[1] = new Computer();
p[2] = new Audio();

얼핏 보면 코드만 길어진 거 같은데 뭐가 좋을까라는 생각이 들지만, 아래 코드를 보면 생각이 바뀔 것이다.

class Buyer {		// 구매자
    int money = 1000;	// 소지금액
    int bonusPoint = 0;	// 소유 포인트
    Product[] cart = new Product[10]; // 10개까지 담을 수 있는 카트
    int i=0; // cart 인덱스
    void buy (Product p){
        if(money < p.price) {
            System.out.println("잔액이 부족합니다.");
            return;
        }
        if(i>=10){
            System.out.println("카트가 다 찼습니다.");
            return;
        }
        money -= p.price;
        bonusPoint += p.bonusPoint;
        cart[i++] = p; // p를 cart에 담고 인덱스 증가시킴
        System.out.println(p + "을/를 구입하셨습니다.");
    }
}

Buyer 클래스에 물건을 10개까지 담을 수 있는 카트를 만들었다. 이렇게 해놓으면 다른 물건을 사도 cart 배열에 다 담을 수 있게 된다. 만약 다형성을 이용하지 않는다면 물건별로 따로 배열을 관리해야 할 것이다. 이렇게 구매 목록이 관리가 되니 영수증 출력도 가능해진다.

// Buyer 클래스 내부
void bill() {			// 영수증 출력
    int sum = 0;		// 구입한 물품의 가격합계
    String itemList ="";	// 구입한 물품목록

    for(int i=0; i<cart.length;i++) {
        if(cart[i]==null) break;
        sum += cart[i].price;
        itemList += cart[i] + ", ";
    }
    System.out.println("구입하신 물품의 총금액은 " + sum + "만원입니다.");
    System.out.println("구입하신 제품은 " + itemList + "입니다.");
    System.out.println("현재 포인트는 " + bonusPoint + "점 입니다.");
}

// 메인 내부
Buyer b = new Buyer();
// 현재 1000만원, 적립 포인트 0점
b.buy(new Tv()); // "Tv을/를 구입하셨습니다."
b.buy(new Computer()); // "Computer을/를 구입하셨습니다."
b.bill();
// "구입하신 물품의 총금액은 300만원입니다."
// "구입하신 제품은 Tv, Computer, 입니다."
// "현재 포인트는 30점 입니다."
b.buy(new Audio()); // "Audio을/를 구입하셨습니다."
b.bill();
// "구입하신 물품의 총금액은 350만원입니다."
// "구입하신 제품은 Tv, Computer, Audio, 입니다."
// "현재 포인트는 35점 입니다."

 

[쿠키글] Vector 클래스

Vector 클래스는 가변 배열 기능이 있는 클래스이다.

  - 클래스 내부에는 Object 타입의 배열이 있는데, Object 클래스는 모든 클래스의 조상이기 때문에 이 배열에는 모든 타입의 객체를 저장할 수 있다.

  - 또한 가변 배열인 만큼 우리가 배열의 크기를 신경 쓰지 않아도 알아서 조절이 된다는 장점이 있다.

'Java' 카테고리의 다른 글

추상 클래스 작성하기  (0) 2022.05.11
추상 클래스, 추상 메서드  (0) 2022.05.05
instanceof 연산자  (0) 2022.05.03
참조변수의 형변환  (0) 2022.04.20
다형성  (0) 2022.04.19