[DDD] FACTORY(팩터리)

0️⃣1️⃣·2024년 2월 1일
0

DDD

목록 보기
3/22

정의

어떤 객체나 전체 AGGREGATE를 생성하는 일이 복잡해지거나 내부 구조를 너무 많이 드러내는 경우 FACTORY가 캡슐화를 제공해준다.

어떤 객체를 생성하는 것이 그 자체로도 주요한 연산이 될 수 있지만 복잡한 조립 연산은 생성된 객체의 책임으로 어울리지 않는다. 이런 책임을 클라이언트에 두면 이해하기 힘든 볼품없는 설계가 만들어질 수 있다. 클라이언트에서 직접 필요로 하는 객체를 생성하면 클라이언트 설계가 지저분해지고 조립되는 객체나 AGGREGATE의 캡슐화를 위반하며, 클라이언트와 생성된 객체의 구현이 지나치게 결합된다.

복잡한 객체와 AGGREGATE의 인스턴스를 생성하는 책임을 별도의 객체로 옮겨라. 이 객체 자체는 도메인 모델에서 아무런 책임도 맡지 않을 수도 있지만 여전히 도메인 설계의 일부를 구성한다. 모든 복잡한 객체 조립 과정을 캡슐화하는 동시에 클라이언트가 인스턴스화되는 객체의 구상 클래스를 참조할 필요가 없는 인터페이스를 제공하라. 전체 AGGREGATE를 하나의 단위로 생성해서 그것의 불변식이 이행되게 하라.

설계요건

각 생성 방법은 원자적이어야 하며, 생성된 객체나 AGGREGATE의 불변식을 모두 지켜야 한다. FACTORY는 일관성 있는 상태에서만 객체를 만들어 낼 수 있어야 한다. ENTITY의 경우 이것은 전체 AGGREGATE를 생성하는 것을 의미하며, 이떄 모든 불변식을 충족하고 선택적인 요소도 추가될 것이다. 불변적인 VALUE OBJECT의 경우에는 모든 속성이 올바른 최종 상태로 초기화되는 것을 의미한다. 인터페이스를 통해 올바르게 생성할 수 없는 객체를 요청할 수 있다면 예외가 발생하거나 또는 다른 어떤 메커니즘이 작동해서 더는 적절하지 않은 반환값이 사용될 수 없도록 보장할 것이다.

FACTORY는 생성된 클래스보다는 생성하고자 하는 타입으로 추상화돼야 한다.

위치선정

이미 존재하는 AGGREGATE에 요소를 추가해야 한다면 해당 AGGREGATE의 루트에 FACTORY METHOD를 만들 수도 있다. 이렇게 하면 한 요소가 추가될 때 AGGREGATE의 무결성을 보장하는 책임을 루트가 담당하고, 동시에 모든 외부 클라이언트에게서 AGGREGATE의 내부 구현을 감출 수 있다.

생성된 객체를 소유하지는 않지만 다른 객체를 만들어내는 것과 밀접한 관련이 있는 특정 객체에 FACTORY METHOD를 두는 것이다. 이렇게 하면 한 객체의 데이터나 규칙이 객체를 생성하는 데 매우 크게 영향을 주는 경우 어떤 다른 곳에서 해당 객체를 생성할 때 생산자의 정보를 필요로 하는 것을 줄일 수 있다. 아울러 생산자와 생성된 객체 사이의 특별한 관계를 전해주기도 한다.

FACTORY METHOD는 동일한 AGGREGATE에 속하지 않는 ENTITY를 만들어낸다.

  • TradeOrder라는 추상 클래스를 Brokerage Account를 통해서 만들 수 있다. 즉, TradeOrder를 만들기 위해 필요한 정보들을 Brokerage Account가 가지고 있으면 다른 애그리거트의 FACTORY METHOD를 제공할 수 있다.

특정 AGGREGATE안의 어떤 객체가 FACTORY를 필요로 하는데 AGGREGATE 루트가 해당 FACTORY가 있기에 적절한 곳이 아니라면 독립형 FACTORY를 만들면 된다. 하지만 AGGREGATE 내부에 접근하는 것을 제한하는 규칙은 지켜지게 하고 AGGREGATE 외부에서는 FACTORY의 생성물을 일시적으로만 참조하게 해야 한다.

  • 일시적으로 참조한다는 것은 필요한 정보만을 획득하고 인스턴스를 바꾸는 것은 지양해야 한다는 것을 의미한다.

생성자만으로 충분한 경우

클래스가 타입인 경우, 클래스가 어떤 계층구조의 일부를 구성하지 않으며, 인터페이스를 구현하는 식으로 다형적으로 사용되지 않는 경우

클라이언트가 STRATEGY를 선택하는 한 방법으로서 구현체에 관심이 있는 경우

  • 모든 컬렉션은 구상 구현체에게서 클라이언트를 분리하는 인터페이스를 구현하지만, 그러한 컬렉션은 모두 생성자를 직접 호출해서 생성되는 형태

  • 구상 생성자를 더 선호하는 이유는 어떤 구현을 선택하느냐에 따라 성능 차이가 발생할 수 있으므로, 애플리케이션에서는 구현 선택을 제한하고 싶을 수 있음(이상적인 FACTORY라면 그와 같은 사항을 조정할 수 있을수도..)

List<Integer> list = new ArrayList<>();

클라이언트가 객체의 속성을 모두 이용할 수 있어서 클라이언트에게 노출된 생성자 내에서 객체 생성이 중첩되지 않는 경우

생성자가 복잡하지 않은 경우

  • 다른 클래스의 생성자 내에서 생성자를 호출하지 않도록 주의
  • 생성자는 극도로 단순해야 한다.
  • AGGREGATE와 같이 복잡한 조립과정을 거쳐 만들어지는 것을 생성하려면 FACTORY가 필요

공개 생성자가 FACTORY와 동일한 규칙을 반드시 준수해야 하는 경우. 이 때 해당 규칙은 생성된 객체의 모든 불변식을 충족하는 원자적인 연산이어야 한다.

인터페이스 설계

  • FACTORY의 메서드 서명을 설계할 때는 해당 FACTORY가 독립형이냐 FACTORY METHOD냐에 관계없이 다음의 두 가지 사항을 명심해야 한다.

각 연산은 원자적이어야 한다. 복잡한 생성물을 만들어내는 데 필요한 것들을 모두 한 번에 FACTORY로 전달해야 한다. 또한 생성이 실패해서 특정 불변식이 충족되지 못하는 상황에서는 어떤 일이 일어날지 결정해야 하는데, 이 경우 예외를 던지거나 단순히 널(null) 값을 반환할 수도 있다. 일관성을 지키고자 FACTORY에서 발생하는 실패에 대해 코딩 표준을 동비할 것을 고려해본다.

FACTORY는 자신에게 전달된 인자와 결합될 것이다. 입력 매개변수를 선택하는데 신경쓰지 않는다면 의존성의 덫이 만들어질 수 있다. 결합의 정도는 인자를 어떻게 처리하느냐에 따라 달라진다. 인자가 단순히 생성물에 들어가는 것이라면 가장 의존성이 적당한 상태다.

불변식 로직의 위치

  • FACTORY의 책임은 그것이 만들어내는 객체나 AGGREGATE의 불변식이 충족되도록 보장하는 것

  • FACTORY에서 불변식 검사를 하는 것은 AGGREGATE 규칙에는 특히 잘 맞지만, 다른 도메인 객체에 속한 FACTORY METHOD의 경우에는 그렇지 못하다.

ENTITY FACTORY와 VALUE OBJECT FACTORY

  • VALUE OBJECT는 불변적, 생성물이 완전히 최종적인 형태로 만들어짐

  • ENTITY FACTORY는 유효한 AGGREGATE를 만들어 내는 데 필요한 필수 속성만 받아들이는 경향이 있음

저장된 객체의 재구성

  • 저장된 객체를 자바 메모리로 가져오는 과정을 재구성이라고 할 수 있음(ORM)

재구성에 사용된 ENTITY FACTORY는 새로운 ID를 할당하지 않는다.

객체를 재구성하는 FACTORY는 불변식 위반을 다른 방식으로 처리할 것이다.

  • 객체를 생성할 때 불변식이 어겨지면 객체의 생성을 중단하는 것과는 달리, 재구성된 객체에 대해서는 불변식이 충족되지 않는 경우 탄력적으로 대응할 수 있는 정책이 존재해야 함

FACTORY는 객체의 생성과 재구성이라는 생명주기 전이를 캡슐화 한다.

0개의 댓글