interface와 abstract class의 차이

허세진·2026년 2월 1일

backend

목록 보기
15/20

interface와 abstract class는 추상화를 구현하는 방법이다.

그래서

interface와 abstract class를 알아보기 전에 추상화가 뭔지부터 알아보려고한다.

추상화

추상화는 객체의 공통된 핵심 역할과 기능을 정의하는 객체지향의 특징이다.

추상화가 필요한 이유

  1. 객체가 많아질수록 세부 구현에 직접 의존하면 코드가 복잡해진다.
  2. 공통된 역할과 기능을 기준으로 객체를 다루기 위해 필요하다.
  3. 변경에 강한 구조를 만들기 위해 필요하다.

이제 추상화가 뭐고, 왜 필요한지 알아봤으니 추상화를 구현하는 방법(interface, abstract class)에 대해서 알아보자

interface

interface는 객체가 수행해야 할 공통된 역할과 기능을 정의한 타입이다.

interface의 특징

  • 구현을 포함하지 않고 기능의 명세만 가진다.
  • 여러 클래스가 하나의 interface를 구현할 수 있다.
  • interface 타입으로 객체를 참조할 수 있다.
  • 구현 클래스는 인터페이스의 모든 메서드를 반드시 구현해야 한다.

interface 예시

interface를 적용 안 했을 때 문제

class CardPayment {
    void pay() {
        System.out.println("카드 결제");
    }
}

class OrderService {
    private CardPayment payment = new CardPayment();

    void order() {
        payment.pay();
    }
}

결제 방식이 1개일 때는 문제가 없다.

하지만

요구사항(결제 방식)이 추가된다면..?

class OrderService {
    private CardPayment cardPayment = new CardPayment();
    private KakaoPay kakaoPay = new KakaoPay();

    void order(String type) {
        if (type.equals("CARD")) {
            cardPayment.pay();
        } else if (type.equals("KAKAO")) {
            kakaoPay.pay();
        }
    }
}

OrderService가 결제 방식의 모든 종류를 알고 있고 새로운 결제 수단을 추가 할 때마다 OrderService를 수정해줘야한다. (OCP 위반)

interface를 적용하면?

interface Payment {
    void pay();
}
class OrderService {
    private Payment payment;

    OrderService(Payment payment) {
        this.payment = payment;
    }

    void order() {
        payment.pay();
    }
}

OrderService는 결제 방식이 몇 개인지 자체를 모른다.
-> 결제방식이 늘어나도 OrderService를 수정할 필요가 없다.

그래서 interface를 사용하면 확장성있게 개발을 할 수 있다.

interface는 언제 사용하는가?

여러 구현이 하나의 역할을 가질 때

서로 다른 구현을 하나의 타입으로 묶어 동일한 방식으로 다루기 위해 필요하다.

구현 교체 가능성이 있을 때

구현 변경이 클라이언트 코드에 영향을 주지 않도록 하기 위해 필요하다.

역할 중심 설계가 필요할 때

객체를 구현이 아니라 책임과 의미 기준으로 설계하기 위해 필요하다.

abstract class

abstract class는 추상 메서드와 구현 메서드를 함께 가질 수 있는 클래스 타입이다.

abstract class 특징

  • 인스턴스를 직접 생성할 수 없다.
  • 단일 상속만 가능하다.
  • 추상 메서드와 일반 메서드를 함께 가질 수 있다.
  • 공통 상태(필드)를 가질 수 있다.

abstract class 예시

abstract class를 적용 안 했을 때의 문제

요구사항
모든 결제는 결제 시작 로그, 실제 결제 처리, 결제 완료 로그 순서로 동작해야 한다.

class CardPayment {
    void pay() {
        System.out.println("결제 시작");
        System.out.println("카드 결제 처리");
        System.out.println("결제 완료");
    }
}
class KakaoPayment {
    void pay() {
        System.out.println("결제 시작");
        System.out.println("카카오페이 결제 처리");
        System.out.println("결제 완료");
    }
}

공통 로직(결제 시작/완료)이 모든 클래스에 중복되고, 결제 흐름이 바뀌면 모든 클래스를 수정해야하는 문제점이 있다.

abstract class를 적용하면?

abstract class Payment {

    public final void pay() {
        beforePay();
        doPay();       // 하위 클래스가 구현
        afterPay();
    }

    protected void beforePay() {
        System.out.println("결제 시작");
    }

    protected void afterPay() {
        System.out.println("결제 완료");
    }

    protected abstract void doPay();
}

pay()의 전체 흐름을 상위 클래스에서 고정시키고, 실제 결제 방식만 하위 클래스에 위임하도록한다.

하위 클래스 구현

class CardPayment extends Payment {
    @Override
    protected void doPay() {
        System.out.println("카드 결제 처리");
    }
}

class KakaoPayment extends Payment {
    @Override
    protected void doPay() {
        System.out.println("카카오페이 결제 처리");
    }
}

이렇게 abstract class를 적용하면

공통 로직 제거, 결제(여기서는 결제) 흐름 한 곳에서 관리, 전체 프로세스의 일관성 보장 등의 장점이 있다.

abstract class는 언제 사용하는가?

공통된 상태(필드)나 구현 로직을 여러 클래스가 공유해야 할 때

중복 코드를 제거하고 기본 동작을 제공하기 위해 사용한다.

전체 동작 흐름은 고정하고, 일부 단계만 하위 클래스가 구현하도록 강제하고 싶을 때

뼈대를 상위 클래스에서 통제하기 위해 사용한다.

하위 클래스의 구현 범위와 자유도를 제한하고, 일관된 구조를 유지하고 싶을 때

잘못된 구현을 컴파일할 때 방지하기 위해 사용한다.

interface와 abstract class의 차이

interface와 abstract class의 차이는 크게 목적, 구현 제공 여부, 자유도와 통제, 확장구조, 설계 의도로 나눌 수 있다.

목적

  • interface: 역할을 정의한다.
  • abstract class: 공통 구현과 흐름을 정의한다.

구현 제공 여부

  • interface: 구현을 제공하지 않는다.
  • abstract class: 공통 구현을 제공할 수 있다.

자유도와 통제

  • interface: 구현 클래스의 자유도가 높다.
  • abstract class: 하위 클래스의 구현 범위와 흐름을 제한한다.

확장 구조

  • interface: 여러 개를 구현할 수 있다.
  • abstract class: 하나만 상속할 수 있다.

설계 의도

  • interface: 구현 교체와 결합도 분리를 위해 사용한다.
  • abstract class: 중복 제거와 일관된 구조 강제를 위해 사용한다.
profile
로그를 파고드는 시간을 즐기는 백엔드 개발자, 허세진입니다.

0개의 댓글