요즘 1일 1커밋을 목표로 사이드 프로젝트를 진행중입니다.
애견샵을 관리하는 사이트를 만드는 프로젝트인데, 개 품종, 결재 수단 같은 거의 반 고정적이면서 비즈니스 로직에서 활용하는 데이터가 존재해 어떻게 처리를 할 지 고민하다 Enum을 사용해 처리를 했죠.
그 과정을 아래에 정리해봤습니다.
왜 Enum 을 사용했냐면...
맨 처음 생각한 방법은 데이터별 코드 테이블을 만들어 사용하는 방법이었습니다. 현재 회사에서 같은 방식으로 구성중이라 가장 먼저 생각난 방법입니다. 그러나 같은 이유로, 단점 또한 바로바로 생각이 났죠.
- 데이터를 활용하기 위해서는 반드시 DB를 조회해와야 합니다.
- 실제 비즈니스 로직의 코드 상에는 코드 값이 사용되고있어, 이 값이 의미하는 것을 바로 이해하기 어려웠습니다.
- 만약 코드가 의미하는 데이터가 변경되면(그럴 일은 없을거라고 배웠지만, 실제로 일어나버렸습니다.), 해당 코드를 사용하는 모든 소스를 수정해야했습니다.
- 코드 추가 시, 기존 레거시 코드나 다른 위치에서 어떤 코드를 사용하고 있는지 일일이 찾아 새로운 코드를 정의해야했습니다.
- 서로 다른것을 의미하는 코드가 중복되는 사태가 있었습니다.
- 코드 테이블을 사용하지 않는 경우 클래스마다 전역변수로 값을 선언해 사용했습니다.
이러한 이유로 작년에 Enum 을 활용해 코드를 정리하는 것을 건의했던게 생각나 Enum을 활용하기로 결정했습니다.(안타깝게도 이 건의는 기각됬습니다. ㅜㅜ)
당시 Enum을 활용하자고 건의한 이유는 아래와 같았습니다.
- 코드가 단순해지고 가독성이 매우 좋아집니다.
- 컴파일 시점에서 상수값의 안정성이 보장됩니다.
- 아무래도 Enum이다보니, 코드상에서 값의 의도?가 바로 확인됩니다.(아, 이거 코드구나! 하고)
기초적인 방법
우선, 정말정말 기초적인 Enum 클래스를 작성해봤습니다.
1
2
3
4
|
public enum CustomerType
{
MALTESE, YORKSHIRE_TERRIER, SHIH_TZU, POODLE
}
|
cs |
이 Enum 클래스는 개 품종을 열거하는 클래스인데, 확실히 코드상에서 가독성은 매우 좋아졌습니다. 코드의 의도도 확실히 보이고, 값의 안정성도 보장이 되었습니다.
그런데, 제가 필요한건 또 있었습니다. 이 품종의 한국 표기를 화면에 던져주고 싶었습니다.
위 코드 같은 경우에는 상수값만 존재하기 때문에 알 수가 없습니다.
한 발짝 더
클래스의 변수를 추가해보았습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public enum CustomerType
{
MALTESE("말티즈")
, YORKSHIRE_TERRIER("요크셔 테리어")
, SHIH_TZU("시츄")
, POODLE("푸들");
private String korName;
CustomerType (String korName)
{
this.korName = korName;
}
public String getKorName ()
{
return this.korName;
}
}
|
cs |
이제 getKorName 메서드를 호출하면, 지정한 한국 표기 내용이 반환됩니다. 예제 코드에는 Getter 메서드를 직접 작성했지만, 실제 코드에서는 Lombok @Getter 어노테이션을 사용했습니다.
이렇게 만들고나니, 또 욕심이 생겼습니다. 이 품종을 검색하는 기능을 만들 수 있을까?
기능 추가
한국 표기로 품종을 Like 검색하는 메서드를 추가해봤습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
public enum CustomerType
{
MALTESE("말티즈")
, YORKSHIRE_TERRIER("요크셔 테리어")
, SHIH_TZU("시츄")
, POODLE("푸들");
private String korName;
CustomerType (String korName)
{
this.korName = korName;
}
public String getKorName ()
{
return this.korName;
}
public static List<CustomerType> findEnumByKorNameLike(String korName)
{
List<CustomerType> result = new ArrayList<>();
for(CustomerType type : CustomerType.values())
{
if(type.getKorName().trim().indexOf(korName) > -1)
{
result.add(type);
}
}
return result;
}
}
|
cs |
이제 이 클래스를 사용하는 클래스에서는 아래와 같이 품종을 검색할 수 있습니다.
1
|
List<CustomerType> result = CustomerType.findEnumByKorNameLike("말티즈");
|
cs |
리팩토링
위에서 추가한 메서드를 좀 더 세련되게 리팩토링 해보았습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
public enum CustomerType
{
MALTESE("말티즈")
, YORKSHIRE_TERRIER("요크셔 테리어")
, SHIH_TZU("시츄")
, POODLE("푸들");
private String korName;
CustomerType (String korName)
{
this.korName = korName;
}
public String getKorName ()
{
return this.korName;
}
public static List<CustomerType> findEnumByKorNameLike(String korName)
{
return Arrays.stream(CustomerType.values())
.filter(type -> type.getKorName().trim().indexOf(korName) > -1)
.collect(Collectors.toList());
}
}
|
cs |
더 알아보기
구현하고 싶은 내용은 모두 구현했으니, 마지막으로 Enum 클래스에 대해 좀 더 알아보겠습니다.
- 관련있는 값을 지정, 표현할 수 있습니다.
- 예를 들어, 어떤 데이터의 사용 여부를 A에서는 1/0으로, B에서는 true/false로 관리하고 있다면 아래와 같은 방법으로 처리가 가능합니다.
12345678910111213141516171819202122232425public enum TestEnum{USE(1, true), NOT_USE(0, false);private int aValue;private boolean bValue;TestEnum(int a, boolean b){this.aValue = a;this.bValue = b;}public int getAValue(){return this.aValue;}public boolean getBValue(){return this.bValue();}}cs
- 예를 들어, 어떤 데이터의 사용 여부를 A에서는 1/0으로, B에서는 true/false로 관리하고 있다면 아래와 같은 방법으로 처리가 가능합니다.
- 코드에 의미를 부여해줍니다.
- A라는 상황에서 "1"이라는 값과 B라는 상황에서 "1"이라는 값이 가지는 의미는 분명히 다릅니다.
- 단순히 문자열로 코딩을 하게 되면, 이 의미를 코드를 보고 알 수 없습니다.
123456789101112131415// 문자열만 사용했을 때String value = "1";if (value.equals("1")){...}else if (value.equals("2")){...}else{...}cs - 하지만, Enum 을 사용하게 되면 값의 의미를 코드만 보고도 알 수 있습니다.
123456789101112131415// Enum을 사용했을 때String value = "1";if (value.equals(PaymentType.CASH)){...}else if (value.equals(PaymentType.CARD)){...}else{...}cs
- DB 의존도를 낮출 수 있습니다.
'☕️ JAVA' 카테고리의 다른 글
Try with Resources - 손쉬운 자원 해제 (0) | 2021.03.09 |
---|---|
BufferedReader 가 Scanner 보다 빠른 이유 (0) | 2020.11.08 |
WebSocketSession에서 HttpSession를 얻는 방법 (0) | 2020.09.10 |
Spring AOP와 AspectJ 비교하기 (14) | 2019.12.15 |
이미지를 BLOB 형태로 DB에 저장하기 (5) | 2018.09.09 |