이 글은 프로그래머스 - 실무 자바 개발을 위한 OOP와 핵심 디자인 패턴 강의를 정리한 내용입니다.
Enum은 Enumulation의 줄임말로 열거형이라고 부릅니다. 가장 기본적인 형태는 다음과 같습니다.
CalculateTypeV1
public enum CalculateType {
ADD, MINUS, MULTIPLY, DIVIDE
}
Enum은 단순히 데이터의 타입을 정의할 때 사용한다고 생각하기 쉽지만, 간단한 문법으로 강력한 다형성을 제공해줍니다.
위에서 정의한 Enum을 단순히 데이터 타입 정의 정도로만 사용한다면 다음과 같이 활용할 수 있습니다.
CalculateCommandV1
public class CalculateCommand {
private CalculateType calculateType;
private int num1;
private int num2;
public CalculateCommand(CalculateType calculateType, int num1, int num2) {
this.calculateType = calculateType;
this.num1 = num1;
this.num2 = num2;
}
public CalculateType getCalculateType() {
return calculateType;
}
public int getNum1() {
return num1;
}
public int getNum2() {
return num2;
}
}
ClientV1
public class Client {
public int someMethod(CalculateCommand calculateCommand) {
CalculateType calculateType = calculateCommand.getCalculateType();
int num1 = calculateCommand.getNum1();
int num2 = calculateCommand.getNum2();
int result = 0;
if(calculateType.equals(CalculateType.ADD)) {
result = num1 + num2;
} else if(calculateType.equals(CalculateType.MINUS)) {
result = num1 - num2;
} else if(calculateType.equals(CalculateType.MULTIPLY)) {
result = num1 * num2;
} else if(calculateType.equals(CalculateType.DIVIDE)) {
result = num1 / num2;
}
return result;
}
}
Client
코드를 보면 각각의 CalculateType
에 대해서 각기 다른 분기문이 실행되는 로직을 확인할 수 있습니다.
someMethod
는 파라미터로 받은 CalculateType
과 num1
, num2
파라미터의 값에 따라 다른 결과를 만들어 반환합니다.
위 코드에서 눈여겨 볼 부분은 CalculateType
에 따라서 코드가 분기되고 있다는 점입니다. 즉, enum이 현재 어떻게 활용되고 있는지에 대한 부분입니다.
MainV1
public class BasicEnumExampleMain {
public static void main(String[] args) {
CalculateCommand calculateCommand = new CalculateCommand(
CalculateType.ADD,
100,
3
); // 보통은 클라이언트가 요청할 때 보내준 데이터를 사용
Client client = new Client();
int result = client.someMethod(calculateCommand);
System.out.println(result);
}
}
Main
로직을 살펴보면 CalculateCommand
의 생성자를 통해 적절한 CalculateType
과 num1
, num2
를 포함한 CalculateCommand
인스턴스를 생성해서 Client
의 someMethod
인자로 넘겨주는 것을 확인할 수 있습니다.
👀 물론 위 로직은 예시를 위해 직접 필요한 데이터들을 생성해주었고, 일반적으로는 프론트엔드에서 넘어온 데이터를 처리합니다.
이제 코드를 실행해보면 원하는 계산결과가 잘 출력되는것을 확인할 수 있습니다.
result = 103
위에서 살펴본 코드를 Enum을 좀 더 활용하여 개선해보겠습니다.
CalculateTypeV2
public enum CalculateType {
ADD ((num1, num2) -> num1 + num2),
MINUS ((num1, num2) -> num1 - num2),
MULTIPLY ((num1, num2) -> num1 * num2),
DIVIDE ((num1, num2) -> num1 / num2);
CalculateType(BiFunction<Integer, Integer, Integer> expression) {
this.expression = expression;
}
private BiFunction<Integer, Integer, Integer> expression;
public int calculate(int num1, int num2) {
return this.expression.apply(num1, num2);
}
}
기존 CalculateTypeV1
코드는 단순히 타입만 나열했던것에 비해 V2
코드는 더 복잡해졌습니다. 단순히 타입만 정의한 게 아닌 각 타입에 대한 연산의 행위도 포함하고 있습니다.
Enum에 생성자 코드가 등장하였습니다. 이 생성자는 각 타입의 괄호에 들어가는 값들을 정의해주는 역할을합니다. 이 괄호 부분에 들어간 파라미터가 생성자로 들어온다고 생각하면됩니다.
(자세한건 Java 기본서에 Enum 문법을 더 알아보세요!)
생성자 아래쪽에는 필드가 하나 선언되어있습니다.
BiFunction<a, b, c>은 함수형 인터페이스로 함수를 마치 하나의 타입처럼 다룰 수 있게 해주는 문법입니다.
calculate
메서드는 인자로 받은 두 정수 num1
과 num2
를 각각의 내부 데이터 타입에 정의된 람다식을 사용해 연산한 결과를 반환합니다.
이제 개선된 CalculateTypeV2
에 맞춰 클라이언트 코드 역시 변경해보겠습니다.
ClientV2
public class Client {
public int someMethod(CalculateCommand calculateCommand) {
CalculateType calculateType = calculateCommand.getCalculateType();
int num1 = calculateCommand.getNum1();
int num2 = calculateCommand.getNum2();
int result = calculateType.calculate(num1, num2);
return result;
}
}
ClientV2
는 이전 V1
보다 코드가 훨씬 단순해졌습니다.
가장 눈에 띄는 변화는 기존 V1에 존재하던 분기문이 사라졌다는 점입니다. 이제 CalculateType
에 대한 calculate
메서드만 호출해주면 연산은 enum 코드 안에서 이뤄지기 때문에 더이상 분기문으로 적절한 연산을 Client
에서 수행할 필요가 없어졌습니다.
V1
-> V2
변경에서 중요하게 봐야할 포인트는 다음과 같습니다.
Client
가 CalculateType
에 대한 구체적인 내용을 몰라도됩니다.두 번째 포인트가 특히 중요합니다.
외부에 존재하던 CalculateType
의 연산 로직들이 모두 내부로 들어갔습니다. 결과적으로 관련된 로직들이 모두 enum안에 존재하기 때문에 코드의 응집력이 높아졌다고 얘기할 수 있습니다.
V1
은 Client
가 CalculateType
에 정의된 각각의 타입은 물론 해당 타입이 어떤 연산을 하는지 모두 알고있었습니다. 따라서 CalculateType
에 어떤 변화가 생긴다면 Client
역시 그 변화에 영향을 받을 가능성이 매우 높습니다.
하지만 V2
는 Client
가 더이상 CalculateType
의 세부적인 타입들까지 알고있을 필요가 없습니다. 따라서 CalculateType
의 변화에 비교적 자유롭고, CalculateType
은 이전보다 더욱 추상적인 존재가됩니다.
CalculateType.ADD
보다는 CalculateType.calculate()
가 더 추상적인 코드입니다.
이처럼 Enum을 잘 활용하면 객체지향적인 코드를 작성하는데 큰 도움을 받을 수 있습니다.