본문 바로가기

Java

enum의 ordinary() 메서드 사용.

effective java를 보면
서수가 필요 할 때 enum의 ordinary() 메서드는 가급적 사용하지 말라고 되어있습니다.
enum을 구성하는 값이 지워지거나 하게 되면
ordinary() 메서드에서 리턴되는 순서 값도 같이 변하기 때문입니다.

이런식의 버그는 나중에 어디선가 발생하게 되면
상당히 찾기 난해합니다.

그런데 제가 이번에 ordinary를 쓸모있게 사용한 부분(이라고 혼자 생각하는 부분 ^^)이 있어서 소개하려 합니다.

ordinary 메서드는 enum을 구성 하는 각 값들의 순서를 리턴합니다.

 
일 때, FIELDNAME.NAME.ordinary()는 0을 리턴합니다.
FIELDNAME.PRICE.ordinary()는 1을 리턴하겠죠.

그러다가 PRICE가 빠지게 되면 FIELDNAME.SCORE.ordinary()가 1을 리턴하게 됩니다.

이렇게 가변적인 값을 갖기 때문에 effective java에서는 사용하지 말 것을 권하는데요..

이렇게 가정을 해보겠습니다.
결과 값을
List<String[]> 형으로 반환하는 솔루션이 있습니다.
솔루션이기 때문에 이 부분을 수정 할 수 는 없는 상황입니다.
이 결과를 사용하는 view에서는 배열의 index를 통해서 해당 값에 접근해야 합니다.

각 index는 위 코드 처럼 name price score를 뜻합니다.
즉 [0]=name, [1]=price, [2]=score이죠.

만약 솔루션에서 보여줘야 할 필드가 늘어나면 솔루션에 필드 설정을 해주고
배열의 index는 하나가 늘어나서 [3]=새로운필드 이런식으로 확장이 됩니다.

뭐 한 3, 4개 정도의 인덱스 숫자라면 사용하기 괜찮습니다.

그런데 비지니스가 바뀌고 업무가 늘어나면서
솔루션에서 처리해주고 리턴해줘야 할 필드가 늘어나게 되고 그렇게 되면서, 이 인덱스가 커지게 됩니다.
50개 60개까지 늘어납니다.

이정도 되면 각 인덱스가 어떠한 값을 가르키고 있는지
기억조차 할 수가 없습니다.
특정 필드의 값을 사용하고 싶은데 , 몇 번 인덱스가 그 값인지를 외우지 못 해서
매번 레퍼런스등을 찾아봐야 하죠.

그래도 이정도에서 끝나면 다행인데..
서비스가 변하면 기존에 사용하던 필드를 사용하지 않게 되었습니다.

그럼 이걸 지워야 하는데
무작성 안 쓴다고 빼버리면 전체의 인덱스가 하나씩 밀려버리는 현상이 발생합니다.
즉, 총 60개의 필드를 지정하여 사용하고 있었는데
그중 30번째 필드가 더 이상 필요하지 않아 삭제를 하였더니
전체 index 크기가 59로 변하면서, 기존에 [60]으로 접근하던 소스에서는
ArrayOutOfBoundsException이 발생하게 됩니다.

문제는 이게 런타임Exception이라서
이클립스 같은 IDE 툴에서 보이지 않고
그렇기 때문에 각 소스를 찾아다니며 수정을 해주고

31번째 부터는 모든 index를 -1씩 해줘야 정상적인 값을 가져 올 수 있다는 이야기가 됩니다.

이게 귀찮아서 안 쓰는 필드를 그냥 놔두면..
점점점점 배열의 크기는 커지고
이제 뭐가 쓰는 필드인지 안 쓰는 필드인지조차
모르게 되어버리는거죠...

이 상황을 좀 유연하게 넘어가고 싶었습니다. 그래서 생각한 것이 enum의 ordinary() 메서드 입니다.

enum을 맵퍼처럼 사용을 하였습니다.


이렇게 솔루션에 필드가 추가 되면 그 순서에 맞추어서 enum도 확장해 줍니다.

이정도만 되어도 감이 오시는 분도 계실거에요..

그리고 이 mapper를 사용하여 값을 리턴해주는 domain 클래스를 하나 만듭니다.


mapper의 역할을 하는 enum의 ordinary 값으로 배열에 접근하여 값을 리턴해주는 getter를 포함한 domain 클래스입니다.

일단, enum이 mapper 역할을 하기 때문에
각 인덱스가 무엇을 뜻하는지 알수있기도 하지만
무엇보다도 배열에 직접 접근 하는 것이 아니라 getter를 사용하기 때문에
getter 메서드 이름만으로도 이 값이 무엇을 뜻하는지 알 수 있습니다.

중요한 것은 중간 필드가 삭제 되었을 경우입니다.

위 예에서 sale_cnt라는 필드를 더 이상 사용하지 않아서 빼야 한다고 하면..
그냥 빼면 됩니다.

그러면 기존에 FIELDNAME.SALE_CNT로 접근하던 domain 클래스에서는 컴파일 에러가 발생 할 것입니다.

눈에 보이죠. 컴파일 에러. 이클립스에서 빨강색으로 표시해줍니다.

runtime 에러가 아니기 때문에 표시가 납니다.

그러면 이 getter 메서드에서 빈 값을 리턴해주도록 수정하던가
아니면 getter 메서드 자체를 지워버립니다.

getter메서드 자체가 지워지면 마찬가지로 이 메서드에 접근 하던 클래스등에서 또 컴파일 에러 표시가 날 것입니다.

하지만, 이렇게 지워버리면 위험요소가 존재할 수 있기 때문에
빈 값을 리턴해주도록 수정하고 deprecated 처리를 해주면 되겠죠.

더 중요한 사실은 중간에 필드가 빠졌음에도
기존 처럼 배열의 index를 일일히 재조정 해주지 않아도 된다는 것 입니다.

사실 이런 상황은 특수한 상황입니다.

저런 솔루션을 사용하는 그런 상황에서나 필요한 내용이지만
enum 클래스를 이런식으로도 사용하는구나.. 라는 뜻으로
봐주시면 좋을 것 같습니다.