0. 들어가며🏃

코드를 작성하다 보면 상수를 정의하는 경우가 많이 있습니다.

 

저 역시 최근 자바 코드를 작성하면서 상수들을 하나하나 정의하다 보니.. 그 수가 많아져 이를 관리해야할 필요성을 느끼게 되었습니다. 상수를 어떻게 관리하면 좋을지 고민하다가 도움이 된 자료들이 있어 이번 글에서는 이에 대한 내용을 정리해보려 합니다.



1. 상수를 관리하는 방법 중 안티 패턴💀

우선 자바에서 상수를 관리하는 방법 중 안티 패턴으로 알려진 몇 가지 방법을 먼저 소개하겠습니다.

1) Magic Number

if (nubmer == 3.1415) {...} // 3.1415 => Magic Number

위 코드의 3.1415 같은 수를 Magic Number라고 칭하는데 위와 같이 코드를 작성하면 다음과 같은 문제들이 발생합니다.

 

우선 해당 숫자의 의미를 파악하기가 어렵습니다. 코드 작성자가 PI를 의도하고 3.1415를 적어놨어도 다른 개발자가 이를 바로 파악하기가 쉽지 않을 수 있습니다. 오해할 여지도 생길 수 있죠.

 

또한 Magic Number를 사용하는 곳이 여러 군데라면 이를 한꺼번에 관리하기가 어렵습니다. 예를 들어 매우 긴 코드에서 PI를 의도한 3.1415를 곳곳에 사용했다고 생각해보죠! 그런데 갑자기 3.1415 대신 3.14를 씁시다.라고 요구사항이 변경된다면 매우 슬픈 일이 되어버립니다. ㅜㅜ 

 

따라서 위와 같은 코드는 간단하지만 아래와 같이 바꿔주면 좀 더 좋은 코드가 될 것 같습니다.

private static final double PI = 3.14159; // 접근 제어자는 상황에 따라..

if (number == PI) {...} // Magic Number 대신 상수를 정의해서 사용하자!

2) 상수 인터페이스😦

위 내용과 같이 상수를 특정 클래스에서만 사용하는 경우 해당 클래스 자체에 선언해주는 것이 합리적으로 보입니다. 하지만 여러 클래스에서 사용하는 상수를 정의할 때는 다른 선택지를 고민해봐야겠죠.

 

이때 생각해볼 수 있는 것이 인터페이스입니다. 아래와 같이 코드를 작성하는 것이죠.

public interface Constants {

    public static final double PI = 3.14;
    public static final double EULER_NUMBER = 2.71;

}

언뜻 보기에는 괜찮아 보이고 실제로 자바 라이브러리에서도 상수 인터페이스를 사용한 클래스가 존재합니다. 하지만 이는 안티 패턴으로 취급됩니다. 이에 대한 이유는 아래와 같습니다.

 

이펙티브 자바에 따르면 인터페이스는 타입을 정의하는 용도로만 사용하자라고 되어있습니다. 즉, 인터페이스는 자신의  인스턴스가 무엇을 할 수 있는지 클라이언트에게 알려주는 역할을 하기 위한 목적으로 만들어졌습니다. 상수 인터페이스는 이러한 인터페이스의 목적을 무시하는 행위이기 때문에 좋은 방식이라고 할 수 없는 것 같습니다. 

 

또한 인터페이스를 구현한 객체와 그 하위 객체에서 상수 인터페이스에서 정의한 상수를 건드릴 경우 사이드 이펙트가 발생할 가능성이 생기기 때문에 결국 안티 패턴으로 지정된 것 같습니다.


2. 그럼 상수들 관리는 어떻게 하지❓❓

위와 같은 안티 패턴을 제외하고 생각해볼 수 있는 것이 열거 타입 enum유틸리티 클래스입니다.

 

관리하려는 상수가 열거 타입으로 나타내기 적합하다면 enum을 사용할 수 있지만 제가 고민했던 부분과는 좀 달랐고 enum만으로도 정리할 내용이 방대하기 때문에 이번 글에서는 다루지 않고 추후 기회가 되면 해당 내용에 대해 정리해보도록 하겠습니다.

 

다음으로 인스턴스화가 불가능한 유틸리티 클래스를 사용해 상수들을 관리하는 방법이 있습니다.

 

유틸리티 클래스의 코드를 먼저 살펴보면 아래와 같습니다.

public final class Constants {

    private Constants() {} // 인스턴스화 방지

    public static final double PI = 3.14;
    public static final double AVOGADROS_NUMBER = 6.022_140_857e23;

}

상수 인터페이스와 형태가 비슷하죠? 인터페이스 대신 클래스를 사용하고 private 생성자를 만듦으로써 상수를 관리하는 방식입니다.

 

위와 같은 방식을 사용하면 해당 클래스의 접근 제어자를 통해 상수의 사용 범위를 효과적으로 제한할 수 있으며, 쓸 때 없는 인스턴스화도 방지할 수 있고, 상속으로 인한 사이드 이펙트 역시 막을 수 있습니다. 

 

따라서 유틸리티 클래스를 사용한다면 상수들을 적절히 관리할 수 있겠다라는 생각이 듭니다!


3. 결론😀

자바에서 적절히 상수들을 관리하는 방법으로는 아래와 같은 방법을 사용하면 좋을 것 같습니다.

  1. 특정 클래스에서만 사용하는 상수라면 해당 클래스에서 상수를 정의해주자.
  2. 여러 군데에서 사용하는 상수라면 enum 혹은 유틸리티 클래스를 사용해보자.

 

 

반응형
복사했습니다!