[교재 EffectiveJava] 아이템 22. 인터페이스는 타입을 정의하는 용도로만 사용하라

반응형
728x90
반응형

상수 인터페이스

인터페이스는 자신을 구현한 클래스의 인스턴스를 참조할 수 있는 타입 역할을 한다. 클래스가 어떤 인터페이스를 구현한다는 것은 자신의 인스턴스로 무엇을 할수 있는지를 클라이언트에 얘기해주는 것이다. 인터페이스는 이 용도로만 사용해야한다. 예외적으로 상수 인터페이스라는 것은 static final 필드로만 가득찬 인터페이스인데, 메서드가 존재하지 않는다. 

public interface PhysicalConstantsInterface {
    static final String MESSAGE = "Hello";
    static final String ALERT = "World";
}

 

상수 인터페이스는 클래스에서 정규화된 이름을 사용하는 것을 피하고자 인터페이스에 구현한 것이다. 상수 인터페이스는 잘못 사용한 예다.

public class MyClass implements PhysicalConstants {
    public static void main(String[] args) {
        // 인터페이스를 구현해서 PhysicalConstants.를 생략할 수 있다.
        // 안티패턴 - 인터페이스의 원래 의도를 오염시킨다.
        // 인터페이스의 의도는 타입을 정의하는 것인데, MyCalss가 PhysicalConstants 타입인가? 라고 한다면 아니다.
        // 네임스페이스 생략을 위한 구현이다. 부적절하다.
        System.out.println(BOLTZMANN_CONSTANT);
    }
}

클래스 내부에서 사용하는 상수는 외부 인터페이스가 아니라 내부 구현에 해당한다. 따라서 상수 인터페이스를 구현하는 것은 내부 구현을 클래스의 API로 노출하는 행위다. 클래스가 어떤 상수 인터페이스를 사용하든 사용자에게는 아무런 의미가 없다. 오히려 클라이언트 코드가 내부 구현에 해당하는 이 상수들에 종속되게 한다. 

 

 

대안

상수를 공개할 목적이라면, 특정 클래스나 인터페이스와 강하게 연관된 상수라면 그 클래스나 인터페이스 자체에 추가해야한다. 열거 타입으로 나타내기 적절한 상수라면 열거 타입(ENUM)으로 만들어 공개하면 된다. 그것도 아니라면, 인스턴스화 할 수 없는 유틸리티 클래스(private 생성자)에 담아 공개하자.

 

유틸리티 클래스
public class PhysicalConstants {
    /* 인스턴스화 방지 */
    private PhysicalConstants() {}

    public static final String MESSAGE = "Hello";
    public static final String ALERT = "World";
}

 

호출
public class Main {
    public static void main(String[] args) {
        // PhysicalConstants physicalConstants = new PhysicalConstants() // 에러
        
        System.out.println(PhysicalConstants.MESSAGE);
        System.out.println(PhysicalConstants.ALERT);
    }
}

 

 

반응형

Designed by JB FACTORY