Enum 이란?
- 서로 관련된 상수들의 집합을 타입으로 정의한 것
- 단순 static final 상수보다 타입 안정성이 높음 (컴파일 타임에 오타나 잘못된 값을 방지)
작성 예시
public enum ProductStatus{
FOR_SALE, // 판매 중
OUT_OF_STOCK, // 품절
DISCONTINUED, // 단종
DELETED; // 관리자에 의해 삭제됨
}
객체 지향적 활용 방법
1. 상태에 따른 판단을 스스로 한다.
안티 패턴
public enum ProductStatus{
FOR_SALE, // 판매 중
OUT_OF_STOCK, // 품절
DISCONTINUED, // 단종
DELETED; // 관리자에 의해 삭제됨
}
/*주문 재고 차감*/
public void decreaseStockForOrder(int orderQuantity) {
if (this.status == ProductStatus.DISCONTINUED) {
throw new IllegalArgumentException("단종된 상품으로 주문할 수 없습니다.");
}
if (this.status == ProductStatus.OUT_OF_STOCK || this.stock == 0) {
throw new IllegalArgumentException("품절된 상품으로 주문할 수 없습니다.");
}
if (this.stock < orderQuantity) {
throw new IllegalArgumentException("상품의 재고가 부족합니다. (현재 재고: " + this.stock + ")");
}
int remainingStock = this.stock - orderQuantity;
this.updateStock(remainingStock);
}
상품의 상태에 따라 주문을 막아야하는 경우, Enum 스스로가 이를 판단해서 결과만 넘겨주는 편이 훨씬 좋다.
수정된 코드
@Getter
public enum ProductStatus{
FOR_SALE("판매중"),
OUT_OF_STOCK("품절"),
DISCONTINUED("단종됨"),
DELETED("삭제됨");
// 에러코드를 위한 상태 String 값 추가
private final String description;
ProductStatus(String description) {
this.description = description;
}
// 주문 가능 상태 여부 판단
public boolean isOrderable(int stock) {
if (this == DISCONTINUED || (this == OUT_OF_STOCK && stock == 0))
return false;
return true;
}
}
/*주문 재고 차감*/
public void decreaseStockForOrder(int orderQuantity) {
// statuts가 상태에 대한 판단을 담당
if (!this.status.isOrderable(this.stock)) {
throw new IllegalArgumentException("상품을 주문할 수 없습니다."
+ "( 상태 :" + this.status.getDescription()
+ " 재고: " + this.stock + " )");
}
if (this.stock < orderQuantity) {
throw new IllegalArgumentException("상품의 재고가 부족합니다. (현재 재고: " + this.stock + ")");
}
int remainingStock = this.stock - orderQuantity;
this.updateStock(remainingStock);
}
2. 상태 자신의 다음을 안다.
안티 패턴
public enum OrderStatus {
PENDING, //준비중
SHIPPING, //배송중
COMPLETED, //배송완료
CANCELED //주문취소
}
주문 상태에 대한 enum이 있다. 이 enum은 분명한 단계가 존재한다. 그런 경우, 상태 자신이 다음 상태를 알고 있는 것이 객체 지향적으로 좋은 구조이다.
수정된 코드
public enum OrderStatus {
PENDING {
@Override public OrderStatus next() { return SHIPPING; }
},
SHIPPING {
@Override public OrderStatus next() { return COMPLETED; }
},
COMPLETED {
@Override public OrderStatus next() {
throw new IllegalStateException("이미 완료된 주문입니다");
}
},
CANCELLED {
@Override public OrderStatus next() {
throw new IllegalStateException("취소된 주문은 진행할 수 없습니다");
}
};
public abstract OrderStatus next();
}
Order order = Order.create(customer, product, 2);
order.advance(); // PENDING → SHIPPING
order.advance(); // SHIPPING → COMPLETED
order.advance(); // IllegalStateException: 안전한 시끄러운 실패
수정에 대한 장점
1. 상태와 관련된 로직이 한 곳에 응집됨 (응집도 상승)
- 새로운 상태가 추가되더라도 enum 내부 함수만 수정하면 됨
2. if-else 문이 줄어들어 가독성이 좋아짐
3. 함수 재사용 가능
'Java > 객체 지향' 카테고리의 다른 글
| SOLID 원칙 (0) | 2026.07.14 |
|---|---|
| 정적 팩토리 메서드 (0) | 2026.06.15 |
| 상속(Inheritance) VS 합성(Composition) (0) | 2026.06.15 |
| 방어적 복사 (0) | 2026.06.15 |
| 값 객체(Value Object)와 불변성 (0) | 2026.06.12 |