BackEnd/Spring

[Java] Interface

bora-ovo 2025. 3. 26. 20:18

1. 인터페이스란 무엇인가

: 클래스들이 반드시 구현해야만 하는 메소드들을 정리해둔 틀

  • 목적 : 다양한 기능을 하는 클래스들 간에 공통적인 기능을 강제하기 위한 것, like 설계도/계약서
  • 형태 : 상수 + 추상메소드 + default/정적메소드
  • 특징 : 다중구현 가능, 객체 생성(new) 불가능

 

예시로 Animal이라는 interface와 강아지, 새의 class를 만들어 보겠다.

// 인터페이스
public interface Animal {
	// 추상 메소드 선언
    public void move();
}
// Dog 클래스
public class Dog implements Animal {
	// Animal에 있는 move() 메소드 구현하기
	@Override
    public void move() {
    	System.out.println("강아지가 걸어갑니다.")
    }
}

// Bird 클래스
public class Bird implements Animal {
	// Animal에 있는 move() 메소드 구현하기
    @Override
    public void move() {
    	System.out.println("새가 걸어갑니다.")
    }
}

 

여기서 Dog와 Bird는 걸어다닐 수 있다는 공통점을 가지고 있다.

이러한 공통점을 Animal이라는 인터페이스에서 move()라는 추상메소드로 제공할 수 있다는 것이다.

 

이렇게 인터페이스를 클래스에서 구현하려면 인터페이스에 있는 기능은 강제적으로 모두 구현해야한다.

 

만약 Animal에 move() 뿐 아니라 fly()라는 추상메소드가 존재한다면, 강아지는 날지 못하기 때문에

Dog Class 는 Animal 인터페이스내의 모든 기능을 구현해낼 수 없어 해당 인터페이스를 사용할 수 없다.

 


2. 인터페이스는 왜 써야할까?

만약 인터페이스가 없는 경우 클래스로만 작성한다면 중복된 메소드를 계속해서 새로 만들어주어야 한다.

예시로 카드, 계좌이체, 간편결제 등의 결제 시스템을 각각 Class라고 생각해보자.

 

// 결제하는 수단마다 메소드가 존재해야 함
public  class PaymentProcessor {
    public void payWithCard(Card card) {
        System.out.println("카드로 결제합니다.");
    }

    public void payWithBankTransfer(BankTransfer bankTransfer) {
        System.out.println("계좌이체로 결제합니다.");
    }

    public void payWithKakaoPay(KakaoPay kakaoPay) {
        System.out.println("카카오페이로 결제합니다.");
    }
}

 

인터페이스가 없다면 카드, 계좌이체, 카카오페이 등 다양한 결제방식에  중복되는 기능이 있음에도 불구하고 계속 새롭게 만들어야 한다.

이러한 경우에는 하나의 중복된 기능을 고치려고 해도 모든 class 에서 수정을 해야하며, 새로운 방식이 도입될 떄에도 매번 새롭게 작성해주어야 하는 단점이 있다. 이를 유지보수가 힘들고, 확장성이 낮다고 표현한다.

 

public interface PayMethod {
    void pay();  // 모든 결제 수단이 반드시 구현해야 할 돈을 지불하는 기능
}
public class Card implements PayMethod {
    @Override
    public void pay() {
        System.out.println("카드로 결제합니다.");
    }
}

public class BankTransfer implements PayMethod {
    @Override
    public void pay() {
        System.out.println("계좌이체로 결제합니다.");
    }
}

public class KakaoPay implements PayMethod {
    @Override
    public void pay() {
        System.out.println("카카오페이로 결제합니다.");
    }
}
// No interface 예시와 같은 PaymentProcessor 이지만
// 여기서는 어떤 결제수단이던지 pay() 메소드 하나면 끝남
public class PaymentProcessor {
    public void processPayment(PayMethod method) {
        method.pay();
    }
}

public class Main {
    public static void main(String[] args) {
        PaymentProcessor processor = new PaymentProcessor();

        PayMethod card = new Card();
        PayMethod bank = new BankTransfer();
        PayMethod kakao = new KakaoPay();

        processor.processPayment(card);
        processor.processPayment(bank);
        processor.processPayment(kakao);
    }
}

 

이렇게 되면 하나의 메소드로 모든 것을 처리할 수 있고,

유지보수를 할 때에도 PayMethod에서만 수정하면 모든 곳에 적용할 수 있으며

구현 클래스만 추가하면 끝이기 때문에 확장성에도 용이하다.