본문 바로가기
언어

[Java] 다형성 Ploymorphism

by 코린이 프로도 2022. 11. 8.
반응형

개요


  API 서버를 개발하던 중 여러 형태의 Request 클래스를 이용하여 하나의 DB 테이블에 저장하기 위해 하나의 entity 클래스로 변환해야하는 일이 생겼다. 각 Request별로 메소드를 만들어 변환시켜 주기에는 재사용되는 소스코드도 많았고 번거로웠다. 다행히 Request 클래스들은 중복되는 필드가 많아 하나의 부모를 상속받고 있는 하위클래스였다. 

 그래서 이 상속 관계를 활용해 불필요한 소스코드를 줄이고 깔끔하게 설계하기 위해서 Java 언어의 특징인 '다형성'에 대해 다시 한 번 정리해 보았다.

다형성


다형성은 다양한 형태를 가질 수 있는 성질을 의미한다. Java 언어가 가진 특성 중 하나라고 할 수 있다.

장점은 반복되는 형태를 개선하여 불필요한 소스코드를 줄이고 유지 보수를 용이하게 하는 데 있다.

구현 방법은 추상 클래스, 인터페이스 상속, 오버라이딩, 업캐스팅 등을 활용하는 복합적인 형태로 구현한다. 글만 봐서는 잘 모르겠다. 바로 예시를 통해 알아보겠다. 

예시


 아래 예시는 Product 부모 클래스의 상속을 받은 Shoe, Laptop 클래스의 관계를 나타낸다.

  • 중복되는 name, price 필드는 부모 클래스의 것을 이용하고 각 자식 클래스별 고유 성질을 나타내는 필드는 따로 추가하였다.
  • 객체 생성 시 초기화를 위한 생성자 함수를 작성했다.
  • 각 자식클래스는 getDetail() 메소드를 오버라이딩했고 일부 필드 값을 확인하기 위해 getter도 넣어줬다.
public class PloymorphismTest {

}

class Product {
    private String name;
    private String price;

    public Product(String name, String price) {
        this.name = name;
        this.price = price;
    }
    public void getDetail() {
        System.out.println("product name : " + name +
                ", product price : " + price);
    }
}

class Shoe extends Product{
    private String size;
    private String color;

    public Shoe(String size, String color) {
        super("신발", "10000");
        this.size = size;
        this.color = color;
    }

    public String getSize() {
        return this.size;
    }

    @Override
    public void getDetail() {
        System.out.println("size : " + this.size + ", color : " + this.color);
    }
}

class Laptop extends Product{
    private String os;
    private String ram;
    private String hdd;

    public Laptop(String os, String ram, String hdd) {
        super("노트북", "2000000");
        this.os = os;
        this.ram = ram;
        this.hdd = hdd;
    }

    public String getOs(){
        return this.os;
    }

    @Override
    public void getDetail() {
        System.out.println("os : " + this.os  + ", ram : " + this.ram + ", hdd : " + this.hdd);
    }
}

 위에 작성된 클래스를 이용한 테스트에 앞서 업캐스팅에 대해 간략히 설명 하자면,

업캐스팅

캐스팅은 형변환을 말한다. 

업캐스팅은 자식 클래스를 부모클래스로 형변환 한다는 것이다. 

위 소스코드를 활용해 예시로 작성해 보자면 Product product = new Shoe("250", "노랑"); 와 같이 표현할 수 있다.

이렇게 업캐스팅을 사용하는 주된 이유는 '다형성'에 있다. 풀어서 설명하자면 상위 클래스(Person) 하나만으로 다양한 하위 클래스 (Shoe, Laptop 등)를 활용할 수 있다. 예를 들어, Shoe, Laptop 클래스는 상위 클래스의 메소드인 getDetail() 메소드를 오버라이딩 했는데, 업캐스팅을 한 Product는 getDetail() 메소드를 호출하면 하위 클래스의 메소드가 호출된다. 어떻게 보면 Product 클래스로 하위 클래스를 동적으로 사용 가능한 것 같다.

이제 좀더 이해가 쉽게 테스트한 결과를 확인해 보자.

테스트

public class PloymorphismTest {

    public static void main(String[] args) {

        Product product = new Product("기본상품", "100");
        Product product1 = new Shoe("250", "노랑");
        Product product2 = new Laptop("윈도우", "8", "1");

        product.getDetail();
        product1.getDetail();
        product2.getDetail();

        System.out.println("=========================================");

        methodTest(product);
        methodTest(product1);
        methodTest(product2);

    }

    public static void methodTest(Product product) {
        if(product instanceof Shoe) {
            System.out.println("shoe instance!!");
            System.out.println(((Shoe) product).getSize());
        }
        if(product instanceof Laptop) {
            System.out.println("Laptop instance!!");
            System.out.println(((Laptop) product).getOs());
        }
    }
}

===================== 결과 ===========================

product name : 기본상품, product price : 100
size : 250, color : 노랑
os : 윈도우, ram : 8, hdd : 1
=========================================
shoe instance!!
250
Laptop instance!!
윈도우

 위 테스트의 결과를 보면 

  • 업캐스팅하여 getDetail() 메소드를 호출하면 각 자식클래스의 오버라이딩된 메소드가 호출되는 것을 알 수 있다. 만약 오버라이딩 되어 있지 않다면, 부모 클래스의 메소드가 호출될 것이다.
  • 난 이게 제일 마음에 드는데, 각 자식클래스를 매개변수로한 메소드를 여러개 만들 필요 없이 부모클래스를 매개변수로 받는 메소드를 하나만 만들어도 그 매개변수의 instance는 자식 클래스의 instance로 유지된다. 하위 클래스에만 있는 필드에 값을 저장하고 업캐스팅을 하여 매개변수로 넘긴다 하더라도 그 값은 유지되는 것이다.
반응형