Java

추상클래스 (abstract class), 인터페이스(interface) 비교 정리,, 나의 숙원사업

티끌모아코더벗어나기 2023. 6. 11. 02:01

 

그 동안 개발을 진행하면서 추상 클래스와 인터페이스를 많이 사용해왔지만,

대충 느낌으로만 ,, 진행했던 제 자신을 반성하기 위해 글을 적습니다,,

 

 

 

판다와 호랑이를 구현해볼 것이고..

오늘 코드의 주인공은 푸바오와 건곤이 입니다.

 

 

이 둘의 공통점은

1. 동물이다.

2. 먹이를 먹고 잠을 잔다.

 

 

이 글에서만 푸바오와 건곤이의 차이점을 강제로 설정하자면,

푸바오는 뛰는 기능(?) 이 없고 건곤이만 뛸 수 있습니다.

 

다이어그램

 

 

 

이 공통점과 차이점을 이용하여 그린 다이어그램입니다.

 

 


 

[인터페이스 Runnable]

public interface Runnable {
    void run();
}

 

run()

인터페이스 메소드이기에 무조건 상속받는 곳에서 Override 해야합니다!


 

[추상클래스 Animal]

import java.time.LocalTime;

public abstract class Animal {

    AnimalType animalType;
    String name;

    public Animal(AnimalType animalType, String name) {
        this.animalType = animalType; // 초식, 육식
        this.name = name;
    }

    public abstract void eat(Food food);
    // enum Food (BAMBOO, MEAT) 

    public void sleep() {
        LocalTime now = LocalTime.of(23,0);
        if (now.getHour() > 22) {
            System.out.println("동물들은 22시 이후에 잠에 듭니다.");
        }
    }
}

 

animalType

초식 / 육식이라는 타입을 갖고 있습니다.

 

name

각각의 이름을 갖고 있습니다.

 

eat()

동물들은 먹이를 먹는다. 그러나 각자의 먹는 방식이나 먹이가 다릅니다.

추상메소드이기에 확장하는 곳에서 무조건 Override 해야합니다.

 

sleep()

동물들은 잠을 잔다. 설정상, 동물들은 22시면 무조건 잠이 듭니다.

일반메소드이지만, 추상클래스 안에 들어있어 확장하는 곳에서 Override할지말지는 선택사항입니다.


[Panda] 

public class Panda extends Animal {

    public Panda(AnimalType animalType, String name) {
        super(animalType, name);
    }

    @Override
    public void eat(Food food) {
        if (food == Food.BAMBOO) {
            System.out.println(this.name + "는 대나무만 먹습니다");
        }
    }
}

 

판다 클래스는 추상클래스인 Animal을 확장하고 있습니다.

Animal에서 eat() 메소드만 추상클래스로 선언되어있기에 이를 꼭 Override 해야합니다.

이 글의 푸공주께서는 대나무만 먹는가봐요..


[Tiger]

public class Tiger extends Animal implements Runnable {

    public Tiger(AnimalType animalType, String name) {
        super(animalType, name);
    }

    @Override
    public void eat(Food food) {
        if (food == Food.MEAT) {
            System.out.println(this.name + "는 고기를 먹습니다.");
        } else {
            System.out.println(this.name + "는 고기가 아닌 것은 먹지 않습니다.");
        }
    }

    @Override
    public void run() {
        System.out.println(this.name + "는 빠르게 달립니다.");
    }

    @Override //todo 사실 override가 필요없습니다. 왜일까요?
    public void sleep() {
        LocalTime now = LocalTime.of(2, 0);
        if (LocalTime.now().getHour() > 0) {
            System.out.println(this.name + "는 0시 이후에 잠에 듭니다.");
        }
    }
}

다음은 우리 건곤이!

건곤이는 추상클래스인 Animal을 확장하고 있으며, Runnable 인터페이스를 상속받고 있습니다!

 

Animal에서 eat() 메소드만 추상클래스로 선언되어있기에 이를 꼭 Override 해야하며,

Runnable 인터페이스에 있는 메소드 또한 무조건 Override해야하기에 run() 메소드를 Override하고 있네요.

 

그리고!

Animal 클래스 안에 있는 sleep() 또한 Override하고 있는데..!

이는 선택사항입니다. 이를 Override하지 않으면, 동물들은 무조건 22시 이후에 잠이 들텐데,

이 글의 건곤이는 0시 넘어서만 잠에 들기 때문에 따로 Override 해주었습니다.

 

그렇지만, 잘- 생각해보면 sleep() 구현 시, override가 필요하지 않을 것 같은데 그렇지 않나요?

 


자, 그래서 우리 에버랜드에 이 친구들을 생성하여 구현한 메소드들을 실행해보았습니다.

  1. 각자의 먹이에 맞게 메세지가 잘 출력되었습니다.
  2. panda.run()은 실행할 수 없습니다.
    사유: run 메소드가 존재하는 Runnable 인터페이스를 판다 클래스가 상속받지 않았기 때문입니다.

  3. tiger.run() -> 건곤이는 뛸 수 있다고 설정했기 때문에 Runnable 인터페이스를 상속받아 건곤이는 뛸 수 있게 되었습니다.

  4. panda.sleep() -> 푸바오는 Animal 클래스를 확장했지만, 그 안에 있는 sleep 메소드를 따로 Override 하지 않았기에 기본적으로 22시 이후에 잠이 들게 됩니다.

  5. tiger.sleep() ->  건곤이 또한 Animal 클래스를 확장했으며 푸바오와는 다르게 sleep 메소드를 다시 구현하여 0시 이후에나 잠이 들도록 설정되었습니다!

 

 

간단하게 예시를 들어 추상메소드 / 추상클래스 / 인터페이스 들을 살펴보았는데요...

이들에 대한 이론적인 속성들은 다른 블로그에서 더 잘 정리해주셔서

저는 코드를 활용하여 이해되도록 글을 작성해보았습니다!

읽어주셔서 감사합니다!