☕️ 인터페이스(Interface)란?
인터페이스는 자바에서 클래스들이 구현해야 하는 동작을 지정하는 용도로 사용되는 추상 자료형이다.
인터페이스는 interface 키워드를 붙여 선언할 수 있으며, 기본적으로는 상수와 추상메서드로 구성된다. 하지만 자바8부터는 default 메서드와 static 메서드를 지원한다.
interface InterfaceSample {
public static final int NUM = 10; // public static final 생략 가능. 컴파일 시에 자동 생성
public abstract void calc(); // public abstract 생략 가능. 컴파일 시에 자동 생성
default void defaultMethod() { // Java8부터 사용 가능한 default 메서드
// ...
}
static void staticMethod() { // Java8부터 사용 가능한 static 메서드
// ...
}
}
☕️ 인터페이스(Interface)의 특징
- 인터페이스는 interface 키워드를 사용하여 정의한다.
- 인터페이스는 상수와 추상메서드로 구성되어 있다. (자바8부터 default와 static 메서드 사용 가능)
- 인터페이스 안의 모든 상수는 public static final 타입이다. (생략 가능)
- 인터페이스 안의 모든 추상메서드는 abstract public 타입이다. (생략 가능)
- 추상클래스와 마찬가지로 인스턴스를 생성할 수 없다.
- 인터페이스는 다른 인터페이스를 extends 키워드로 상속받을 수 있으며, 다중 상속이 가능하다.
- 클래스에서 인터페이스의 구현은 implements 키워드를 사용하여 구현할 인터페이스를 지정 후,
추상메서드를 모두 오버라이드하여 내용을 완성해야 한다.
☕️ 인터페이스(Interface)의 활용
인터페이스는 다음의 그림과 같이 구성할 수 있다.
개발 코드가 객체를 직접호출하는 것이 아니라 인터페이스를 중간에 두면, 개발 코드는 구현 객체를 몰라도 인터페이스를 통해 객체 호출이 가능하다. 이는 상황에 따라 객체가 변경된다 하더라도 개발 코드는 영향을 받지 않음을 의미하게 된다. (= 느슨한 결합)
조금 더 상세한 예제를 통해 어떻게 느슨한 결합을 유도하는지 알아보자.
주문을 처리하는 OrderServiceImpl 클래스와 할인정책을 적용할 수 있는 FixDiscountPolicy, RateDiscountPolicy 클래스가 존재한다고 가정해 보자. (*FixDiscountPolicy는 고정 할인 정책이며, RateDiscountPolicy는 정률 할인 정책)
만약 OrderServiceImpl 클래스가 FixDiscountPolicy 또는 RateDiscountPolicy 클래스와 직접 연결되어있다면, 정책이 변경될 때마다 OrderServiceImpl 클래스의 수정이 불가피할 것이다.
반면, 아래의 그림과 같이 DiscountPolicy라는 인터페이스를 통해 느슨한 결합으로 구성할 경우, OrderServiceImpl를 수정할 필요 없이 정책을 변경할 수 있다.
실제 코드를 통해 확인해보자.
DiscountPolicy 인터페이스는 가격을 받아 계산을 할 수 있는 메서드(discount)를 가지고 있다.
public interface DiscountPolicy {
double discount(long price);
}
이제 DiscountPolicy를 구현한 FixDiscountPolicy와 RateDiscountPolicy를 살펴보자.
FixDiscountPolicy는 무조건 100원을 할인해 주며, RateDiscountPolicy는 가격의 10%를 할인해 준다.
@Slf4j
public class FixDiscountPolicy implements DiscountPolicy {
@Override
public double discount(long price) {
log.info("FixDiscountPolicy 호출");
log.info("판매가격 = {}", price);
log.info("할인 적용 가격 = {}", price - 100);
return price - 100;
}
}
@Slf4j
public class RateDiscountPolicy implements DiscountPolicy {
@Override
public double discount(long price) {
log.info("RateDiscountPolicy 호출");
log.info("판매가격 = {}", price);
log.info("할인 적용 가격 = {}", price - (price * 0.1));
return price - (price * 0.1);
}
}
이제 OrderServiceImpl를 살펴보자.
OrderServiceImpl는 FixDiscountPolicy와 RateDiscountPolicy를 직접 호출하는 것이 아니라 DiscountPolicy를 호출한다.
인터페이스를 사용함으로써 상황에 따라 DiscountPolicy의 실제 구현체인 FixDiscountPolicy 또는 RateDiscountPolicy를 호출할 수 있게 되는 것이다.
@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class OrderServiceImpl {
private final DiscountPolicy discountPolicy;
public double order(long price) {
return discountPolicy.discount(price);
}
}
DiscountPolicy의 구현체는 자바 Config를 통해 선택할 수 있다.
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Bean
public DiscountPolicy discountPolicy() {
// return new FixDiscountPolicy();
return new RateDiscountPolicy();
}
}
이처럼 인터페이스를 사용할 경우, Config파일의 수정이 있었지만 OrderServiceImpl 입장에서는 어떠한 정책을 사용하는지에 대해서 알 필요가 없어진다. 즉, 인터페이스를 통해 느슨한 결합을 도모할 수 있다.
References.
1. KADOSHoly - 인터페이스(interface)의 이해 및 사용하는 이유
2. RyanGomdoriPooh - 자바 인터페이스(Java Interface)는 무엇인가?
3. Inpa - 인터페이스(Interface) 문법 & 활용 - 완벽 가이드
'Java' 카테고리의 다른 글
[Java] 오버로딩(Overloading)과 오버라이딩(Overriding) (0) | 2023.08.02 |
---|---|
[Java] 추상클래스와 인터페이스 비교 (0) | 2023.07.29 |
[Java] 추상 클래스(Abstract Class) (0) | 2023.07.26 |
[Java] 래퍼 클래스(Wrapper Class)와 박싱(Boxing), 언박싱(Unboxing) (0) | 2023.07.25 |
[Java] final 제어자 (0) | 2023.04.21 |