인터페이스(Interface)란?
극단적으로 동일한 목적하에 동일한 기능을 수행하게끔 강제하는 것이 인터페이스의 역할이자 개념이다.
자바의 다형성을 극대화하여 개발코드 수정을 줄이고 프로그램 유지보수성을 높이기 위해 인터페이스를 사용한다.
인터페이스의 요소로는 추상메서드, 상수, 디폴트메서드, 정적메서드, private메서드가 있다.
인터페이스가 클래스와 다른점은 추상메서드로만 이루어져 있다는 점이다.
인터페이스 안에 변수를 선언하게 되면 상수가 된다.
default method, static method, private method는 java8부터 사용할 수 있게 되었다.
기본적으로 인터페이스가 구현을 갖지 못하니까 중복 구현의 오류가 발생할 수 있고 이것을 방지하기 위해 기본적으로
제공되는 메서드이다.
public interface inTest {
//상수
public int Num = 0;
//추상메서드
void absMethod(int a, int b);
//디폴트 메서드
default void deMethod(int a, int b){
//구현부
}
//정적 메서드
static void stMethod(int a, int b){
//구현부
}
}
상수는 인터페이스에서 값을 정해줄것이니 함부로 바꾸지 말고 제공하는 값만 참조하라는 것이다.
추상메서드는 가이드만 해줄테니 오버라이딩해서 재 구현하라는 것이고
디폴트메서드는 기본적으로 제공은 해주지만 구현부를 바꾸고 싶다면 재정의하라는 것이다.
정적메서드는 인스턴스 생성과 상관없이 인터페이스 타입으로 호출하는 메서드이며
인터페이스에서 제공해주는것으로 무조건 사용해야 한다.
private메서드는 인터페이스 내에서 사용하기 위해 구현한 메서드이고 구현하는 클래스에서 재정의 할 수 없으며
java9부터 사용이 가능하다.
인터페이스 문법과 다형성 이해
인터페이스는 interface 키워드를 통해 선언할 수 있으며 implements 키워드를 통해 일반클래스에서 인터페이스를
구현할 수 있다.
인터페이스에서는 추상메서드가 사용된다고 했는데 클래스에서와는 다르게 abstract 키워드가 없어도
추상메서드가 된다.
인터페이스에 선언했다는 것은 인터페이스에 있는 작업들을 가져다 작업하라고 설계하는 것이라고 볼 수 있다.
클래스를 만들고 인터페이스를 implements 해주면 오버라이드를 해야한다.
만약 인터페이스에 선언한 추상메서드가 전부 다 필요한것이 아니라면 필요한 메서드만 남겨두고 지운 뒤
클래스를 abstract으로 만들어주면 된다.
인터페이스를 구현한 클래스는 인터페이스 타입으로 변수를 선언하여 인스턴스를 생성할 수 있다.
인터페이스는 구현 코드가 없기 때문에 타입상속이라고도 한다.
예제코드
/*
고객센터에서는 전화가 오면 일단 대기열에 저장된다.
상담원이 지정되기 전까지 대기상태가 되며 각 전화가
상담원에게 배분되는 정책은 여러 방식으로 구현될 수 있다.
- 상담원 순서대로 배분
- 대기가 짧은 상담원 먼저 배분
- 우선순위가 높은(숙련도가 높은) 상담원에게 먼저 배분
*/
//interface
public interface Scheduler {
public void getNextCall();
public void sendCallToAgent();
} //interface End
//impl RoundRobin class
public class RoundRobin implements Scheduler {
@Override
public void getNextCall(){
System.out.println("상담전화를 순서대로 대기열에서 가져옵니다.");
}
@Override
public void sendCallToAgent(){
System.out.println("다음 순서의 상담원에게 배분합니다.");
}
} //RoundRobin End
//impl Priority
public class PriorityAllocation implements Scheduler {
@Override
public void getNextCall() {
System.out.println("고객 등급이 높은 고객의 Call을 먼저 가져옵니다.");
}
@Override
public void sendCallToAgent() {
System.out.println("업무 숙련도가 높은 상담원에게 먼저 배분합니다.");
}
}//Priority End
//impl Least
public class LeastJob implements Scheduler {
@Override
public void getNextCall() {
System.out.println("상담전화를 순서대로 대기열에서 가져옵니다.");
}
@Override
public void sendCallToAgent() {
System.out.println("현재 상담업무가 없거나 상담대기가 가장 적은 상담원에게 먼저 배분합니다.");
}
} //Least End
//Test Class
import java.io.IOException
public class SchedulerTest{
public static void main(String[] args) throws IOException {
System.out.println("전화 상담원 할당방식을 선택하세요");
System.out.println("R : 한명씩 차례대로");
System.out.println("L : 대기가 적은 상담원 우선");
System.out.println("P : 우선순위가 높은 고객 우선 숙련도 높은 상담원");
int ch = System.in.read();
Scheduler scheduler = null;
if(ch == 'R' || ch == 'r') {
scheduler = new RoundRobin();
}else if(ch == 'L' || ch == 'l') {
scheduler = new LeastJob();
}else if(ch == 'p' || ch == 'p') {
scheduler = new PriorityAllocation();
}else {
System.out.println("지원되지 않는 기능입니다");
return;
}
scheduler.getNextCall();
scheculer.sendCallToAgent();
}//main End
}//Test End
하나의 클래스는 여러개의 인터페이스를 상속 받을 수 있다.
단, 이때 default method의 이름이 중복되는 경우에는 재정의 해야 한다.
인터페이스 간에도 상속이 가능한데 구현이 없으므로 extends 뒤에 여러 인터페이스를 상속 받을 수 있다.
구현 내용이 없기 때문에 타입상속(Type Inheritance)라고 한다.
예제코드
//interface Buy
public interface Buy {
void buy();
default void order() {
System.out.println("구매 주문");
}
} //buy End
//interface Sell
public interface Sell{
void sell();
default void order(){
System.out.println("판매 주문");
}
} //sell End
//impl class
public class Customer implements Buy, Sell {
@Override
public void buy() {
System.out.println("customer buy");
}
@Override
public void sell() {
System.out.println("customer sell");
}
@Override
public void order() {
System.out.println("customer order");
}
public void sayHello() {
System.out.println("Hello");
}
} //impl class End
//Test Class
public class CustomerTest {
public static void main(String[] args) {
Customer customer = new Customer();
customer.buy();
customer.sell();
customer.order();
customer.sayHello();
Buy buyer = customer;
buyer.buy();
buyer.order();
Sell seller = customer;
seller.sell();
seller.order();
}
} //Test class End
위 예제와 같이 여러 인터페이스를 상속 받을 수 있다.
Buy와 Sell 인터페이스에 order라는 default method 가 동일한 이름을 갖고 있다.
그래서 Customer클래스에서 둘을 오버라이드 할때 buy와 sell은 문제없이 오버라이드 되지만
order에 대해서는 Buy인터페이스에 있는 order를 사용할지 sell에 있는 order를 사용할지 정해줘야 한다.
여기서 재정의하지 않으면 두 인터페이스에서 동일한 디폴트메서드를 갖고 있으므로 어느것을 사용해야 할지 몰라서
오류가 발생한다.
이클립스와 인텔리제이 두가지에서 오버라이드 했을 때 차이가 발생하는데 이클립스에서는 오버라이드 하도록 하면
order를 제외한 두 메서드만 오버라이드 한뒤 다시 Buy와 Sell중에서 선택하도록 한다.
Buy를 선택한다면
order안에 Buy.super.order(); 가 들어가있는 상태로 생성된다. Sell을 선택하면 당연히 Sell.super.order();가 될것이고.
보이는 그대로 Buy인터페이스에 있는 order를 쓴다는 것이고 Sell에 있는 order를 쓴다는 것이다.
인텔리제이는 좀 다른게 그냥 구현부가 하나도 없이 생성된다.
@Override
public void order() { } 이렇게 생성되기 때문에 그냥 넘어가면 안되고 재정의를 해줘야 한다.
예제에서 결과값은
customer buy
customer sell
customer order
Hello
customer buy
customer order
customer sell
customer order
가 출력된다.
결과값을 보면 디폴트 메서드인 order를 구현된 인스턴스의 메서드로 호출되는 것을 확인할 수 있다.
여기서 Buy의 order를 출력하고 싶다거나 Sell의 order를 출력하고 싶다면 위에 설명했던 것 처럼
order 재정의를 할 때 Buy.super.order(); 혹은 Sell.super.order(); 로 정의해주면 된다.
레퍼런스
● 패스트캠퍼스 올인원 패키지 - 자바 객체지향프로그래밍
'JAVA' 카테고리의 다른 글
템플릿 메서드(Template Method) (0) | 2021.02.02 |
---|---|
싱글톤 패턴(Singleton Pattern) (0) | 2021.02.01 |
생성자(Constructor) (0) | 2021.01.30 |
다형성(polymophism) (0) | 2021.01.29 |
상속(inheritance) (0) | 2021.01.28 |