본문 바로가기
Java

자바에서 상수 정의하기: 추상 클래스와 인터페이스의 활용

by 코더 제이콥 2023. 1. 25.

자바에서 상수를 정의하는 방법은 변수 앞에 제어자 public static final를 붙이면 선언이 가능합니다. 이때 객체지향적으로 설계하기 위해서는 자주 사용하는 상수를 따로 클래스를 만들어 줘야 합니다. 상수들을 정의한 클래스에 가장 중요한 부분은 무엇일까요?

 

바로 해당 클래스는 생성자로 생성되어서는 안 된다는 것입니다.

 

때문에 상수에 관련된 클래스를 정의할 때 추상클래스(abstract class)나 인터페이스(interface)가 자주 쓰입니다. 이 포스팅에서는 왜 두 개가 자주 쓰이는지 차근차근 알아보고자 합니다.

 

1. 추상클래스의 경우

추상 클래스는 구현체가 아니기 때문에 생성자를 통해 생성될 수 없습니다. 이것은 생성자로 생성되어서는 안 된다는 위의 조건에 부합합니다. 물론 추상클래스 말고, 기본 생성자에 private를 붙이면 생성되지 않습니다만... 이런 과정은, 너무 너무 귀찮습니다.

 

따라서 추상 클래스에 필드를 정의하면 추상클래스는 구현체가 아니라는 특징 때문에 생성자로 생성되지 않기에 추상클래스에 상수를 정의하고는 합니다.

 

public abstract class BlogInfo {
    public static final String BLOGGER_NAME = "Hello, World!";
    public static final String BLOG_URL = "https://jaykaybaek.tistory.com";
}

 

다른 클래스에서 참조하기 위해서는

 

public class Test{
    String name = BlogInfo.BLOGGER_NAME;
}

 

이런 식으로 코드를 작성하면 되겠습니다. 또 BlogInfo를 다른 클래스에서 생성하고자 한다면

 

생성이 막히는 것을 알 수 있습니다.

 

2. 인터페이스의 경우

인터페이스에서 필드를 선언하면 자동으로 public static final이 붙습니다. 또 인터페이스는 구현체가 아니기 때문에 생성될 수 없습니다. 귀찮은 것을 싫어하는 개발자의 입장으로는 금상첨화네요. 바로 코드로 확인하겠습니다.

interface BlogInfo {
    String BLOGGER_NAME = "Hello, World!";
    String BLOG_URL = "https://jaykaybaek.tistory.com";
}

앞서 필드에 덕지덕지 붙어 있었던 제어자들이 깔끔하게 사라졌습니다. 인터페이스, 즉 구현체가 아니기 때문에 생성이 불가능해 위의 조건에도 부합합니다. 또 필드를 선언만 하면 컴파일러가 자동으로 상수로 만들어주니 무조건 인터페이스에 상수를 만들면 되겠죠... ?

 

but, 안티패턴

아, 정말 말도 안 되네요. 위의 코드들은 모두 안티패턴입니다.안티패턴인 이유는 위키피디아를 참조해주세요.(https://en.wikipedia.org/wiki/Constant_interface)

 

사실 왜 안티패턴인지도 이해는 갑니다. 인터페이스의 역할이 상수를 정의하는 것은 아니니까요. 따라서 위키피디아에서는 다음과 같은 패턴을 제안합니다. 한번 리팩토링 해보죠.

 

public final class BlogInfo {
    public static final String BLOGGER_NAME = "Hello, World!";
    public static final String BLOG_URL = "https://jaykaybaek.tistory.com";

    private BlogInfo() {
    }
}

 

짜잔. 우선 클래스에 final 제어자를 붙여 변경을 제어했습니다. 또 기본 생성자에 private 접근 제어자를 붙여 객체 생성을 제한했습니다. 또 필드에 상수를 정의한 모습입니다. 이렇게 클래스를 작성하는 것이 위의 두 가지 방법 보다 더 좋은 대안이라고 위키피디아에서는 설명합니다.