모든지 기록하자!

[Java] 인터페이스 ( interface) ( 예제: 상담원 배분) 본문

Java

[Java] 인터페이스 ( interface) ( 예제: 상담원 배분)

홍크 2021. 5. 18. 23:53
728x90

구현 코드가 없는 인터페이스

인터페이스(interfave)는 클래스나 프로그램이 제공하는 기능을 명식적으로 선언하는 역할을 한다.

인터페이스는 추상 메서드와 상수로만 이루어져 있다. 구현 코드가 없기 때문에 인터페이스로

인스턴스를 생성할 수도 없다. 

 

인터페이스 만들기

마우스 오른쪽 -> New -> Interface

 

Calc 인터페이스 만들기

public interface Calc {

	double PI = 3.14;
	int ERROR = -99999999;
	//인터페이스에는 상수와 추상메서드 선언
	
	int add(int num1, int num2);
	int substract(int num1, int num2);  // 인터페이스에서 선언한 메서드는
	int times(int num1, int num2);      // 컴파일 과정에서 추상 메서드로 변환된다.
	int divide(int num1, int num2);
	
 }

인터페이스에 선언한 메서드는 전부 구현 코드가 없는 추상 메서드이다. 이 메서드 들은

public abstract 예약어를 명시적으로 쓰지 않아도 컴파일 과정에서 자동으로 추상 메서드로 변환된다.

그리고 인터페이스에서 선언한 변수는 모두 컴파일 과정에서 값이 변하지 않는 상수로 자동 변환된다.

클래스에서 인터페이스 구현하기

선언한 인터페이스를 클래스가 사용하는 것을 클래스에서 인터페이스를 구현한다(implements)라고 한다.

public class Calculator implements Calc{
}

이렇게 코드를 작성하면 오류가 발생한다.

Calculator 클래스에서 Calc 인터페이스를 구현한다고 했으므로 Calculator 클래스는 추상 메서드 4개

add(), substract(), times(), devide() 를 포함한다. 이 추상 메서드를 구현하지 않으면 Calculator 클래스도 

추상 클래스가 된다. 

public abstract class Calculator implements Calc{

	@Override
	public int add(int num1, int num2) {
		return num1 + num2;
	}

	@Override
	public int substract(int num1, int num2) {
		return num1 - num2;
	}

}

추상 메서드 times()와 divide()를 구현하지 않았으므로 Calculator는 추상 클래스(abstract class)이다.

 

클래스 완성하고 실행하기

Calculator 추상 클래스를 상속받아 CompleteCalc 클래스를 만든다. 아직 구현하지 않은

times()와 divide() 추상 메서드를 이 클래스에서 구현한다.

public class CompleteCalc extends Calculator{

	@Override
	public int times(int num1, int num2) {
		return num1 * num2;
	}

	@Override
	public int divide(int num1, int num2) {
		if(num2 != 0) {
			return num1/num2;
		}
		return ERROR; // num2가 0 , 즉 나누는 수가 0인 경우에 대해 오류 반환
	}

	public void showInfo() { // CompleteCalc 에서 추가로 구현한 메서드
		System.out.println("Calc 인터페이스를 구현하였습니다.");
	}
}

 

테스트 프로그램으로 실행해보자

public class CalculatorTest {

	public static void main(String[] args) {
		
		int num1 = 10;
		int num2 = 2;
		
		CompleteCalc calc = new CompleteCalc();
		System.out.println(calc.add(num1, num2));
		System.out.println(calc.substract(num1, num2));
		System.out.println(calc.times(num1, num2));
		System.out.println(calc.divide(num1, num2));
		calc.showInfo();
		
	}
}

 

구체적인 클래스인 CompleteCalc 클래스만 인스턴스를 생성할 수 있다. Calculator 클래스는 

추상 클래스이므로 인스턴스를 생성할 수 없고, Calc 인터페이스는 추상 메서드만 선언되었기 때문에

인스턴스를 생성할 수 없다.

 

출력 결과

인터페이스의 역할

메서드 선언 부만 있는 인터페이스를 왜 사용하는가?

인터페이스의 역할은 인터페이스를 구현한 클래스가 어떤 기능의 메서드를 제공하는지 명시하는 것이다.

클라이언트 프로그램은 인터페이스에서 약속한 명세대로 구현한 클래스를 생성해서 사용하면 된다.

인터페이스와 다형성

인터페이스를 사용하면 다형성을 구현하여 확장성 있는 프로그램을 만들 수 있다.

클라이언트 프로그램을 많이 수정하지 않고 기능을 추가하거나 다른 기능을 사용할 수 있다.

아래 예제를 확인해보자

 

고객 센터에 전화가 오면 대기열에 저장된다. 상담원이 지정되기 전까지 대기상태가 된다.

각 전화를 상담원에게 배분하는 정책은 여러 방식으로 구현할 수 있다.

1. 순서대로 배분: 모든 상담원이 동일한 상담 건수를 처리하도록 들어오는 전화 순서대로 배분

2. 짧은 대기열 찾아 배분: 고객 대기 시간을 줄이기 위해 상담을 하지 않는 상담원이나 가장 짧은 대기열을 보유한 상담원에게 배분

3. 우선순위에 따라 배분: 고객 등급에 따라 등급이 높은 고객의 전화를 우선 가져와 업무 능력이 좋은 상담원에게 우선 배분한다. 

 

Scheduler 인터페이스를 구현하는 RoundRobin(순서대로),  LeastJob(짧은 대기열 먼저), 

PriorityAllocation(우선순위) 클래스를 직접 만들어 활용해보자

public interface Scheduler {

	void getNextCall(); // 추상메서드 2개 선언
	void sendCallToAgent();
}

Scheduler 인터페이스는 추상 메서드 2개를 선언했다. 이제 Scheduler 인터페이스를 구현하는 각 클래스도

모두 추상 메서드 2개를 구현해야 한다.

 

public class RoundRobin implements Scheduler{

// 상담원 한 명씩 돌아가며 동일하게 상담 업무 배분
	@Override
	public void getNextCall() {
		System.out.println("상담 전화를 순서대로 대기열에서 가져옵니다.");
	}

	@Override
	public void sendCallToAgent() {
		System.out.println("다음 순서 상담원에게 배분합니다.");
	}
}

 

public class LeastJob implements Scheduler{

// 현재 상담 업무가 없거나 상담 개기가 가장 적은 상담원에게 배분
	@Override
	public void getNextCall() {
		System.out.println("상담 전화를 순서대로 대기열에서 가져옵니다.");
	}

	@Override
	public void sendCallToAgent() {
		System.out.println("현재 상담업무가 없거나 상담대기가 가장 적은 상담원에게 할당합니다.");
	}

}

 

public class PriorityAllocation implements Scheduler{

// 고객 등급이 높은 고객의 전화부터 대기열에서 가져와 업무 능력이 높은 상담원 우선 배분
	@Override
	public void getNextCall() {
		System.out.println("고객의 등급이 높은 고객의 전화를 먼저 가져옵니다.");
	}

	@Override
	public void sendCallToAgent() {
		System.out.println("업무 skill 이 가장 높은 상담원의 대기열에 앞에 우선 배분합니다.");
	}
}

 

고객 상담 전화 배분 프로그램을 실행해보자

import java.io.IOException;

public class SchedulerTest {

	public static void main(String[] args) throws IOException {

		// R, L , P
		System.out.println("전화 상담 배분방식을 선택하세요 ");
		System.out.println("R : 한명씩 차례로 할당");
		System.out.println("L : 쉬고 있거나 대기가 가장 적은 상담원에게 할당");
		System.out.println("P : 우선순위가 높은 고객 먼저 할당");
		
		int ch = System.in.read(); // 할당 방식을 입력받아 ch 변수에 대입
		Scheduler scheduler = null;
		
		if( ch == 'R' || ch == 'r') { // 입력받은 값이 R 또는 r이면 
			scheduler = new RoundRobin(); // RoundRobin클래스 생성
		} else if( ch == 'L' || ch == 'l') { // 입력받은 값이 L 또는 l이면
			scheduler = new LeastJob(); // LeastJob 클래스 생성
		} else if (ch == 'P' || ch == 'p') { // 입력받은 값이 P 또는 p이면
		scheduler = new PriorityAllocation(); // PriorityAllocation 클래스 생성
		} else {
		System.out.println("지원하지 않는 기능입니다.");
		return;
	}
		scheduler.getNextCall();         // 어떤 정책인가 상관없이 
		scheduler.sendCallToAgent(); // 인터페이스에 선언한 메서드 호출
	}
}

출력 결과

 

728x90
Comments