Enum 사용법에 대하여 정리 및 사내 공유를 위해 작성
-
해당 글의 용어 및 내용은 Java Enum 활용기 - 우아한형제들 기술 블로그를 많이 참고 하였습니다.
- Enum이란 ?
Enumeration은 프로그래밍언어에서 상수의 그룹을 나타낼 때 사용한다. Enum은 컴파일 당시 우리가 모든 가능한 값을 알고있는 경우 사용된다. 항상 enum안의 상수는 타입이 정해져 있어야 되는 것은 아니다.
Java 1.5버전 부터, enum은 enum 데이터 타입이라고 표시되었다. 자바 enum은 C/C++ enum보다 더 강력한 기능을 제공한다. 자바에서 변수, 메소드 그리고 생성자를 추가할 수 있다. enum의 주된 목적은 우리만의 데이터 타입을 가지기 위해서이다. (Enumberated Data Type)
참고 자바의 enum -
위 정의를 보더라도
Enum은 상수의 그룹
을 나타내기 위하여 사용한다. 라고 선언 되어 있습니다.
과연 상수만을 위하여 Enum을 쓰는것 보다 Enum을 더욱 강력히 사용할 수 없을까? 라는 생각을 가지고 이 글을 보시면 더욱 좋을것 같습니다. - 들어가기 앞서
객체는 상태와 행위를 가진다.
라는 개념에 대해 알고 계시는것이 좋을 것 같습니다.
Enum - 상수의 집합 ?
- 사칙연산을 위한 프로그램을 만든다 할때 연산자를 아래와 같은 Enum으로 구분하여 사용할 수 있을것 같습니다.
OperatorType
은 사칙연산을 위한 연산자를 가지고 있고 여러 클래스에 선언되어 사용하지 않고 연산자를 Enum으로 관리하여 응집도를 높였다고 볼수 있겠네요.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public enum OperatorType { PLUS_OPERATOR("+"), MINUS_OPERATOR("-"), MULTIPLY_OPERATOR("*"), DIVIDE_OPERATOR("/"); private String operator; OperatorType(String operator) { this.operator = operator; } public boolean isEqual(String operator) { return this.operator.equals(operator); } }
OperatorType
은 과연 상태와 행위를 가지는 객체 인가요 ?- 코드를 보시고 상태만 가지고 있다. 라고 생각이 든다면 정답입니다.
- 과연 행위는 어디에 있을까 ?
- 어디선가 아래와 같은 코드를 가지고 있는 클래스를 만들어서 사용해야 할것 입니다.
1 |
|
- 다시 처음 이야기한 객체의 정의에 대해서 생각해봅시다.
객체는 상태와, 행위를 가진다.
OperatorType
은 행위를 가지고 있지 않으니 위 코드에 포함된 행위를OperatorType
으로 옮겨 보겠습니다.
- 위 코드에서의 문제점은 무엇일까요 ?
- 곰곰히 생각을 해봅시다 : )
Enum - 상태와 행위를 한곳에
- 상태와 행위를 한곳에 모아둔
OperatorType
을 먼저 보겠습니다.
1 |
|
- 이제
OperatorType
내부에 선언되어있는 객체들은calculate
라는 행위를 가지게 되었습니다.
이로 인해서 처음에 이야기 했던 객체의 정의를 만족 하게 되었네요 ! - 이전에 행위를 구현했던 코드는 어떻게 변했을까요 ?
참고 Java7 부터 Enum 상수에 추상 메소드를 구현할 수 있습니다.
1 |
|
- 이전엔 Operator 별로 분기를 타며 계산을 하던 메소드가 실제
계산 하라
라는 메시지를 OperatorType에 던지는 단순하고 깔끔한 메소드로 변경 되었습니다. - 여기까지만 보더라도 연산자를 가지고 있는
OperatorType
은 자신이 가지고 있는 책임인계산한다
라는것을 완벽하게 이행 함으로서 외부에선 모든 사칙연산에 관한 계산을OperatorType
을 사용할 수 있게 되었습니다. - 이전에 상태와 행위를 한곳에서 관리 하지 않은 코드를 생각해보시면,
계산 하라
라는 메시지를 누구에게도 던지지 않고 전혀 의미 없는 클래스에서 행위를 구현하여, 다른 클래스에서의 중복이 발생할 가능성이 컸습니다. - 아직 남아 있는 문제점.
- 보시다 시피 Enum 내부 정적 메소드에 파라미터로 전달 받은 Operator에 맞는 상수를 찾아 전달 하고 있습니다.
위와 같은 분기문이 나열되어 있는 것이 좋은 패턴일까요 ?
Enum 리팩토링 - 분기문을 없애보자.
- 분기문을 없애면서 저희는 Java 8 이상을 사용하는 개발자들로 추상메소드를 사용한 방식보다 Lambda를 사용한
OperatorType
으로 리팩토링 해보겠습니다.
1 |
|
1 |
|
- 뭔가 더욱 깔끔하게 리팩토링된것이 느껴진다면 성공입니다 : )
- 추상메소드를 사용한 방식 대신 Lambda로 calculate를 구현 하였습니다.
- Lambda를 사용하기 위하여 @FunctionalInterface를 만들었습니다.
- @FunctionalInterface는 메소드 1개를 가진 인터페이스 입니다.
- Java가 제공하는 함수형 인터페이스도 사용할 수 있습니다. Function<T, R> 은 매개변수 1개를 지원하고 2개는 BiFunction을 사용하셔도 됩니다.
- Lambda를 사용하기 위하여 @FunctionalInterface를 만들었습니다.
- 분기문이 없어진 것을 확인 할 수 있습니다.
- Stream 을 사용하여 분기문을 제거하고 코드의 가독성을 높혀 다른 개발자들이 보더라도 어떤 기능을 하는지 쉽게 알수 있게 되었습니다. : )
- 이처럼 리팩토링을 하게 되어 얻을수 있는 가장 큰 이점은 재사용성과 확장성을 얻을 수 있게 되었다는 것 입니다.
-
다른 클래스에서 사칙연산을 하기 위해선
OperatorType
만 사용하면 될 것이고 새로운 연산자가 추가 되더라도
복잡한 분기문들을 제거 하였기 때문에 상수 정의만 해준다면 어디서든 정상적으로 동작하겠죠 :) - 예제를 사칙연산으로 들었지만 Enum을 사용하는 어느 곳이라도 비슷하게 적용할 수 있을것이라 생각하여 공유드렸습니다.