DDD START! (2)

이유진·2023년 11월 5일
post-thumbnail

앞에서 도출한 모델은 Entity와 Value로 구분할 수 있다

Entity와 Value

Entity

  • 식별자를 가진다
  • Entity를 생성하고 삭제할 때 까지 식별자는 바뀌지 않는다
  • 엔티티의 식별자가 동일하면 같다고 판단 가능하다 → equals and hashcode 메서드로 구현가능

ex) 주문 domain: 주문번호가 주문의 식별자가 된다

  • 주문에서 배송지 주소가 바뀌거나 상태가 변경되어도 주문번호는 바뀌지 않는다

Value

모델 표현력을 증가시킨다
의미를 명확히 표현하기 위해 밸류를 사용할 수 있다

ex) ShippingInfo에서 받는 사람을 나타내는 Value

public class ShippingInfo {
	private String receiverName;
    private String receiverPhoneNumber;
    ...
}

➡️ receiverName, receiverPhoneNumber 는 "받는사람" 에 대한 정보이다
➡️ 두개를 묶어 Receiver Value를 생성할 수 있다

-- Receiver Value 생성
public class ShippingInfo {
	private Receiver receiver;
    ...
}

public class Receiver {
	private String receiverName;
    private String receiverPhoneNumber;
}
  • 받는사람에 대한 로직구현은 Receiver안에서 가능하다

Value가 항상 두 개 이상의 데이터를 가져야 하는 것은 아니다

의미를 명확히 하기 위해 Value를 사용할 수 있다

ex) OrderLine의 price 표현

private class OrderLine {
	private int price;
    ...
}
-- Money Value 생성 후
private class OrderLine {
	private Money price;
    ...
}

private class Money {
	private int value;
    
    // 돈 계산에 대한 로직
}
  • Value 객체의 데이터 생성시에는 기존 데이터를 변경하기보다는 변경한 데이터를 갖는 새로운 Value객체를 생성하는 방식을 선호한다 → Immutable(불변)

왜 불변으로 구현할까?

  • 안전한 코드 작성가능
  • Value의 값이 변경될 때 발생하는 문제를 방지하기 위해 새로운 객체를 생성한다

불변객체 참고 자료

- 불변객체: 생성 후 바꿀 수 없는 객체.
- 객체가 참조(reference)를 통해 공유되어있다면 상태가 언제든지 변경될 가능성이 있다
- 불변객체는 객체를 복제할 때 객체 전체가 아니라 참조만 복사하고 끝난다 → 참조는 보통 객체 그 자체보다 작아서 메모리가 절감되고 프로그램 성능에도 좋다
- 가변객체의 참조를 가지고 있는 어떤 장소에서 객체 변경 시, 해당 참조를 공유하는 모든 곳에서 영향을 받는다
- 멀티스레드 프로그래밍에서 유용하다
- 불변이란 객체가 컴퓨터의 메모리 내에서 쓰기를 할 수 없다는 뜻이 아니다.

ex) String str = “ABC”;

str.toLowerCase() → str 값을 변경하는 것이 아님. 새로운 String 객체가 생성되고, 생성 시 abc 값이 주어진다.
  • Value 객체를 비교할 땐 모든 속성이 같은지 비교한다.

  • 엔티티의 식별자 데이터도 도메인 내에서 특별한 의미를 지니므로 Value로 표현할 수 있다

도메인 모델구현 주의점

도메인 모델에 get/set method 습관적으로 만들지 말자

도메인 객체가 불완전한 상태로 사용되는 것을 막기위해서는 생성시점에 필요한 것을 전달해준다 
→ 생성자를 통해 필요한 데이터를 모두 받아야 한다
→ 생성자를 호출하는 시점에 필요한 데이터가 올바른지 검사할 수 있다

그럼 어떻게 구현해요?

get Method

  • 주문이 배송전인가? 체크
-- 보통 이렇게 하겠죠
public class OrderService {
	public void service_method() {
    	// Order 객체를 만들었다 가정하고
    	if ("PAYMENT_WAITING".equals(order.orderState) && "PREPARING".equals(order.orderState)) {
		// 주문 배송전입니다
		}	
    }
}

이렇게 구현하지 말고,

public class Order {
	private OrderState state; -- enum으로 만들자
    
    public void veryfyNotYetShipped() {
    	if (state != OrderState.PAYMENT_WAITING && state != OrderState.PREPARING) {
        // 주문 배송전입니다
        }
    }
}

public enum OrderState {
	PAYMENT_WAITING, PREPARING, SHIPPED, DELIVERING, DELIVERY_COMPLETED, CANCELED;
}

service method 등에서 state를 getter로 가져와서 비교하지 말고, 해당 도메인 내에서 체크하는 함수를 만들고 그걸 가져다 쓰자

set Method

  • 주문의 state를 cancel로 setting
-- 안좋은예시 (setter 사용)
public class OrderService {
	public void service_method() {
    	// Order 객체 생성했다 생각하고
        order.setState(OrderState.CANCELED); // setter 사용
    }
}

``` java
public class Order {
	private OrderState state; -- enum으로 만들자
    
    -- 도메인 내에 구현
    public void cancel() {
    	this.state = OrderState.CANCELED;
    }
}

public enum OrderState {
	PAYMENT_WAITING, PREPARING, SHIPPED, DELIVERING, DELIVERY_COMPLETED, CANCELED;
}

public class OrderService {
	public void service_method() {
    	// Order 객체 생성했다 생각하고
        order.cancel();
    }
}
  • setter를 다른곳에서 호출하지 말고, 의미있는 메서드를 만들고 그걸 호출하자
profile
BackEnd Developer

0개의 댓글