[JAVA]추상클래스와 인터페이스

JUNYOUNG·2024년 3월 16일
0

인터페이스(Interface)와 추상 클래스(Abstract Class)는 코드의 재사용성과 다형성을 구현하는 데 있어 핵심적인 역할을 합니다.
하지만 언제 인터페이스를 사용하고, 언제 추상 클래스를 사용해야 하는지 혼란스러울 수 있습니다.
이 글에서는 인터페이스와 추상 클래스의 차이점을 명확히 이해하고, 적절한 상황에서 올바르게 사용하는 방법을 알아보겠습니다.

인터페이스란?

인터페이스는 모든 메소드가 추상 메소드로 구성되어 있으며, Java 8 이후부터는 default 메소드와 static 메소드를 포함할 수 있게 되었습니다. 인터페이스는 특정 클래스가 반드시 구현해야 할 메소드를 정의합니다

인터페이스의 예시

인터페이스는 리모컨과 같습니다.
리모컨은 다양한 전자 기기(예: TV, 에어컨, 오디오 시스템)를 제어할 수 있는 버튼(메소드)들의 집합입니다.
각 버튼은 특정 기능(예: 켜기, 끄기, 볼륨 조절)을 정의하지만, 실제 기능의 구현은 연결된 기기에 따라 달라집니다.
즉, '켜기' 버튼은 TV를 켜는 방법과 에어컨을 켜는 방법 사이에 차이가 있을 수 있습니다.
인터페이스는 이러한 '버튼'들을 정의하지만, 실제 '버튼'이 어떻게 작동하는지는 구현하는 객체(기기)에 달려 있습니다.

public interface RemoteControl {
    void powerOn();
    void powerOff();
    void volumeUp();
    void volumeDown();
}

public class Television implements RemoteControl {
    public void powerOn() {
        // TV를 켜는 구체적인 코드
    }

    public void powerOff() {
        // TV를 끄는 구체적인 코드
    }

    // 볼륨 관련 메소드 구현 ...
}

public class AirConditioner implements RemoteControl {
    public void powerOn() {
        // 에어컨을 켜는 구체적인 코드
    }

    public void powerOff() {
        // 에어컨을 끄는 구체적인 코드
    }

    // 볼륨 관련 메소드 구현 ...
}

추상 클래스란?

추상 클래스는 하나 이상의 추상 메소드를 포함하며, 인스턴스를 직접 생성할 수 없습니다. 추상 클래스는 상속을 통해 자식 클래스에 의해 확장되어야 하며, 자식 클래스는 모든 추상 메소드를 구현해야 합니다.

추상 클래스의 예시

추상 클래스는 동물원에 있는 동물과 같습니다.
모든 동물은 '먹기'나 '자기' 같은 공통적인 행동을 공유하지만, 각 동물마다 이러한 행동을 수행하는 구체적인 방법은 다를 수 있습니다.
예를 들어, 고기를 먹는 동물과 풀을 먹는 동물이 있을 수 있습니다.
추상 클래스는 이러한 공통적인 행동을 정의하지만, 실제 행동의 구현은 상속받는 서브클래스에 의해 결정됩니다.

public abstract class Animal {
    public abstract void eat();

    public void sleep() {
        // 모든 동물이 공통으로 사용할 수 있는 '자기' 메소드
        System.out.println("This animal is sleeping.");
    }
}

public class Lion extends Animal {
    public void eat() {
        // 사자가 먹는 구체적인 방식을 구현
        System.out.println("Lion is eating meat.");
    }
}

public class Elephant extends Animal {
    public void eat() {
        // 코끼리가 먹는 구체적인 방식을 구현
        System.out.println("Elephant is eating plants.");
    }
}

Vehicle 추상 클래스는 startEngine이라는 추상 메소드와 stopEngine이라는 일반 메소드를 정의하고 있습니다. Car 클래스는 Vehicle을 상속받아 startEngine 메소드를 구현합니다. 이 예시에서 추상 클래스는 공통적인 기능(stopEngine)을 제공하면서도, 특정 기능(startEngine)에 대한 구현을 강제합니다.

주요 차이점

  • 목적: 인터페이스는 구현해야 할 "메서드"를 정의하는 반면, 추상 클래스는 일부 기능을 상속하고 일부 기능을 강제하는 데 사용됩니다.
  • 다중 상속: 클래스는 여러 인터페이스를 구현할 수 있지만, 하나의 추상 클래스만 상속받을 수 있습니다.
  • 메소드 구현: 인터페이스는 Java 8 이전에는 구현된 메소드를 포함할 수 없었지만, 추상 클래스는 구현된 메소드와 추상 메소드를 모두 포함할 수 있습니다.
  • 상태 관리: 인터페이스는 상태(필드)를 가질 수 없지만, 추상 클래스는 상태(필드)를 가질 수 있습니다.
특성인터페이스 (Interface)추상 클래스 (Abstract Class)
메소드 구현Java 8부터 default 메소드와 static 메소드에 한해서 구현 가능추상 메소드와 구현된 메소드 모두 포함 가능
상태 관리상수(final 변수)만 포함 가능변수를 포함할 수 있으며 상태(값)를 유지할 수 있음
다중 상속지원 (클래스가 여러 인터페이스를 구현할 수 있음)지원하지 않음 (클래스가 하나의 추상 클래스만 상속받을 수 있음)
생성자없음있음 (추상 클래스를 직접 인스턴스화할 수는 없지만, 생성자를 통해 초기화 코드를 포함할 수 있음)
접근 제어자모든 메소드는 public (Java 9부터 private 메소드도 가능)메소드에 다양한 접근 제어자 사용 가능
사용 사례서로 관련 없는 클래스들이 특정 메소드를 구현하도록 강제할 때관련된 클래스들 사이에 코드를 공유하고, 일부 메소드 구현을 강제할 때
인스턴스화불가능불가능 (하지만 추상 클래스를 상속받은 서브 클래스는 인스턴스화할 수 있음)

인터페이스가 적절한 상황:

  1. 다중 구현이 필요한 경우: 여러 클래스가 공통의 인터페이스를 구현하도록 하여 다양한 타입의 객체들이 동일한 동작을 할 수 있도록 할 때 적합합니다. 예를 들어, powerOn, volumeUp 등과 같이 서로 다른 클래스들이 공통의 동작을 공유해야 할 때 사용합니다.
  2. 모듈 간의 결합도를 낮추고자 할 때: 인터페이스를 통해 구체적인 구현 대신 추상화된 계층을 제공함으로써, 코드 간의 결합도를 줄이고 유지보수성 및 확장성을 향상시킬 수 있습니다.

추상 클래스가 적절한 상황:

  1. 공통된 기본 동작이나 상태를 공유해야 할 때: 추상 클래스는 공통된 코드(메소드의 구현)와 상태(필드)를 상속받는 클래스들과 공유할 수 있습니다. 예를 들어, Animal 추상 클래스가 eat과 같은 공통 메소드의 구현을 제공하고, 서브클래스인 Lion, Elephant 등이 이를 상속받는 경우입니다.
  2. 템플릿 메소드 패턴을 구현할 때: 특정 작업의 구조는 유지하면서 일부 단계를 서브클래스에서 구현하도록 할 때 추상 클래스를 사용합니다. 예를 들어, 데이터베이스의 연결, 사용, 종료 과정의 구조를 추상 클래스에서 정의하고, 실제 연결 방법이나 데이터 사용 방법은 서브클래스에서 구체화할 수 있습니다.

결국, 인터페이스는 "할 수 있는 것"을 정의하는 데 초점을 맞추고,
추상 클래스는 "하는 방법"을 일부 공유하면서도 확장을 허용하는 데 사용됩니다.
따라서 설계의 목적과 요구 사항에 따라 적절한 선택을 해야 합니다.

결론

인터페이스와 추상 클래스는 Java에서 코드의 재사용성과 유연성을 높이는 데 사용됩니다. 인터페이스는 주로 다중 상속을 지원하고, 구현해야 할 메소드를 정의할 때 사용됩니다. 반면, 추상 클래스는 공통 기능을 제공하면서 특정 메소드의 구현을 자식 클래스에 강제할 때 사용됩니다. 각각의 특성을 이해하고 상황에 맞게 적절히 선택하는 것이 중요합니다.

profile
Onward, Always Upward - 기록은 성장의 증거

0개의 댓글