추상클래스와 인터페이스를 선택하는 방법

SUM·2025년 1월 2일

결론부터 말하자면, 특정 기능(결제, 배송 등)을 단순히 규약(메서드 시그니처) 으로만 정의할지, 아니면 공통 로직을 일부 구현해놓을 필요가 있는지를 판단해보면 된다.


1. 추상 클래스를 고려해볼 만한 경우

  1. 공통된 코드, 상태가 반드시 존재하고, 이를 그대로 재사용하고 싶을 때
    • 예: 결제 로직에서 모든 결제 수단에 공통적으로 적용해야 하는 메서드가 있다면(수수료 계산의 기본 로직, 로그 기록 등).
  2. “is-a” 관계로 명확히 묶이는 클래스들이고, 단일 상속 구조로 관리해도 무방할 때
    • 자식 클래스가 반드시 상속을 받아야 하며, 다른 클래스를 중복해서 상속받을 필요가 없을 때.

2. 인터페이스를 고려해볼 만한 경우

  1. 다양한 클래스동일한 기능(메서드 시그니처)각자 다르게 구현해야만 할 때
    • 예: 결제 수단이 전혀 공통 로직 없이, 단지 pay() 메서드만 달리 구현하는 상황.
  2. 상속과 무관하게, 다른 클래스(이미 다른 상위 클래스를 상속 중인)라도 ‘이 기능을 구현’할 수 있게 하고 싶을 때
    • 자바는 클래스 단일 상속이므로, 이미 상속받은 부모가 있는 클래스가 또 다른 추상 클래스를 상속받기는 불가능하지만, 인터페이스는 여러 개 implements 가능.

판단 기준 정리

  1. 공통 코드(필드·메서드)를 제공할 필요가 있는가?

    • 있다면추상 클래스 고려
    • 없다면인터페이스로 간단히 규약만 정의
  2. 여러 개의 부모(추상 클래스)를 동시에 상속받아야 할 가능성은?

    • 자바는 단일 상속만 지원하므로, 이미 다른 클래스를 상속받는 중이면 추상 클래스를 더 이상 상속 못 한다.
    • 이 경우 인터페이스를 선택해 다중 구현이 가능하도록 하는 게 이점이 될 수 있음.
  3. 현실 세계 모델링(‘is-a’ vs ‘can do’)

    • 추상 클래스: “결제는 곧 하나의 결제 방식”처럼 클래스 간 상속 계층을 더 강조(“is-a” 관계).
    • 인터페이스: “모든 결제 수단은 결제 기능을 수행할 수 있다”처럼, 행위를 구현(“can do” 관계).

예시로 본다면

  • 결제 로직에서 공통할 수밖에 없는 코드(예: 결제 기록, 기본 에러 처리, 결제 시점 로그 남기기 등)를 자주 쓰고, 상속받는 클래스들이 이것을 그대로 재사용해야 한다면 → 추상 클래스가 더 편하다.
  • 결제 수단마다 거의 전혀 다른 형태로 동작하고, 공통 로직도 별로 없으며, 오직 “pay() 메서드가 있다”만 보장하면 되는 경우 → 인터페이스로 충분하다.

요약

  • 추상 클래스인터페이스 둘 다 “추상화”를 제공하지만, 부분 구현(필드·메서드)을 제공해야 하는지, 다중 상속이 필요한지에 따라 선택이 달라진다.
  • “결제”를 추상 클래스로 만들려면, 여러 결제 방식들(카드, 모바일, 쿠폰 등)이 공통 메서드를 상당 부분 공유할 필요가 있어야 한다.
  • 만약 특정 결제 수단이 이미 다른 클래스를 상속받고 있다면 추상 클래스를 추가로 상속받기 어렵다. 이럴 땐 인터페이스가 낫다.

즉,
1) 상속 구조에서 공통 로직·필드가 필요하면 추상 클래스,
2) 특정 행위만 규약하고 다중 구현이 필요하거나 이미 상속 트리가 있는 경우에는 인터페이스를 쓰면 된다.

profile
백엔드 개발자 SUM입니다.

0개의 댓글