728x90
인터페이스의 역할
- 지금까지 인터페이스를 정의하고 클래스에서 구현하여 사용하는 방법을 알아보았습니다.
- 인터페이스는 어디에 쓰는 코드일까요?
- 자바 8에서 새롭게 추가된 디폴트 메서드와 정적 메서드 구현부(implementation part)가 없다면 인터페이스는 그야말로 껍데기입니다. (디폴트 메서드와 정적 메서드 구현부는 이후에 배울 겁니다)
- 메서드 선언부 (declaration part) 만 있는 인터페이스를 도대체 왜 사용하는지 알아보겠습니다.
- 인터페이스는 클라이언트 프로그램에 어떤 메서드를 제공하는지 미리 알려주는 명세(specification) 또는 약속의 역할을 합니다.
인스턴스가 명세의 역할을 한다? 예시
- Abc 인터페이스를 구현한 A 클래스가 있습니다.
- 그리고 A 클래스를 상속받은 Z 클래스가 있습니다.
- Z 프로그램을 사용하는 누군가가 있다고 가정해보겠습니다.
- 이 사람은 Z 프로그램을 이해하기 위해 Z 프로그램이 상속받은 A 클래스를 이해하려고 합니다.
- 이때, 이 사람은 모든 것이 구현되어 수백 줄의 코드를 가진 A 클래스를 보는 것이 이해하기 편할까요?
- 아니면 선언부로만 이루어져 있는 인터페이스를 보는 것이 이해하기 편할까요?
- 정답은 선언부로만 이루어져 있는 인터페이스를 보는 것입니다.
- 인터페이스의 선언부만 봐도 이 A 클래스를 어떻게 사용할지 알 수 있기 때문입니다.
정리하자면
- 인터페이스의 역할은 인터페이스를 구현한 클래스가 어떤 기능의 메서드를 제공하는지 명시하는 것입니다.
- 그리고 클라이언트 프로그램은 인터페이스에서 약속한 명세대로 구현한 클래스를 생성해서 사용하면 됩니다.
인터페이스와 다형성
- 인터페이스를 사용하면 다형성을 구현하여 확장성 있는 프로그램을 만들 수 있습니다.
- 즉 클라이언트 프로그램을 많이 수정하지 않고 기능을 추가하거나 다른 기능을 사용할 수 있습니다.
- 다음 예제 시나리오를 작성해보면서 인터페이스를 활용한 다형성을 살펴보겠습니다.
- 예제 시나리오 :
- 고객 센터에는 전화 상담을 하는 상담원들이 있다.
- 고객 센터로 전화가 오면 상담원이 지정되기 전까지 대기열에 저장된다.
- 각 전화를 배분하는 정책은 다음과 같습니다.
- 1. 순서대로 배분하기 : 모든 상담원이 동일한 상담 건수를 처리하도록 들어오는 전화 순서대로 상담원에게 하나씩 배분합니다.
- 2. 짧은 대기열 찾아 배분하기 : 고객 대기 시간을 줄이기 위해 상담을 하지 않는 상담원이나 가장 짧은 대기열을 보유한 상담원에게 배분합니다.
- 3. 우선순위에 따라 배분하기 : 고객 등급에 따라 등급이 높은 고객의 전화를 우선 가져와 업무 능력이 좋은 상담원에게 우선 배분합니다.
- getNextCall( ) 은 현재 대기 중인 대기열에서 다음 전화 순번인 고객을 가져오는 메서드이고, sendCallToAgent( ) 메서드는 상담원에게 전화를 배분하는 기능을 담당합니다.
- Scheduler 클래스는 Interface 로 추상 메서드를 가지고 있고 해당 메서드들은 예제 시나리오에 따라 해당 인터페이스를 구현하는 클래스에서 구현합니다.
- Scheduler interface 코드는 다음과 같습니다.
public interface Scheduler {
void getNextCall(); // public abstract 생략
void sendCallToAgent(); // public abstract 생략
}
- 모든 상담원이 공평하게 상담 업무를 분담하는 클래스의 코드는 다음과 같습니다. 인터페이스의 다형성을 보는 것이 목적이므로 실제로 코드를 구현하지는 않았습니다.
public class Distribute implements Scheduler{
@Override
public void getNextCall() {
System.out.println("상담 전화를 순서대로 대기열에서 가져옵니다.");
}
@Override
public void sendCallToAgent() {
System.out.println("다음 순서 상담원에게 배분합니다.");
}
}
- 짧은 줄에 우선적으로 배분하는 클래스 코드는 다음과 같습니다.
public class Shortline implements Scheduler {
@Override
public void getNextCall() {
System.out.println("상담 전화를 순서대로 대기열에서 가져옵니다.");
}
@Override
public void sendCallToAgent() {
System.out.println("현재 상담 업무가 없거나 대가기 가장 적은 상담원에게 할당합니다.");
}
}
- 마지막은 고객 등급이 높은 고객의 전화를 먼저 가져온 다음 업무 능력이 높은 상담원에게 우선적으로 배분합니다.
public class Priority implements Scheduler{
@Override
public void getNextCall() {
System.out.println("고객 등급이 높은 고객의 전화를 먼저 가져옵니다.");
}
@Override
public void sendCallToAgent() {
System.out.println("업무 Skill 값이 높은 상담원에게 우선적으로 배분합니다.");
}
}
- 입력값에 따라서 손님을 배분하는 정책이 달라지는 실행 클래스 코드는 다음과 같습니다.
- 인터페이스를 implements 한 클래스들을 통한 다형성이 확보되는 것을 볼 수 있습니다.
public class SchedulerTest {
public static void main(String[] args) {
System.out.println("전화 상담 할당 방식을 선택하세요.");
System.out.println("1 : 한 명씩 차례대로 할당");
System.out.println("2 : 쉬고 있거나 대기가 가장 적은 상담원에게 할당");
System.out.println("3 : 우선수누이가 높은 고객 먼저 할당");
Scanner scanner = new Scanner(System.in);
int num = scanner.nextInt();
Scheduler scheduler = null;
switch (num) {
case 1 : {
scheduler = new Distribute();
break;
} case 2 : {
scheduler = new Shortline();
break;
} case 3 : {
scheduler = new Priority();
break;
}
default:
System.out.println("지원되지 않는 기능입니다.");
break;
}
scheduler.getNextCall();
scheduler.sendCallToAgent();
}
}
- 코드를 실행한 다음 콘솔 창에 1, 2, 3, 3 이외의 숫자를 입력하면 각각 다른 결과물이 출력되는 것을 볼 수 있습니다.
클라이언트가 클래스를 사용하는 방법
- 앞에서 정의한 상담 전화 배분 정책은 언제든지 바뀔 수 있습니다.
- 예를 들어 회사마다 원하는 배분 정책이 다를 수 있겠습니다. 상담원이 직접 전화를 가져가는 방식 등이 있습니다.
- 이런 경우 추가로 만들어야 하는 배분 정책은 앞에서와 마찬가지로 Scheduler 인터페이스를 구현하는 새 클래스로 만들면 됩니다.
- 어떤 클래스를 구현하건 클라이언트가 인터페이스를 구현한 클래스를 사용하는 코드는 항상
scheduler.getNextCall();
scheduler.sendCallToAgent();
- 이걸로 고정이 됩니다.
- 이렇게 클라이언트 프로그램은 각 클래스의 구현 방법을 몰라도 인터페이스에서 선언된 매개 변수, 반환 값을 보고 클래스를 사용할 수 있습니다.
- 이렇듯 인터페이스는 구현된 클래스를 사용하는 클라이언트 코드와 기능을 제공하는 코드 사이의 약속입니다.