From: 도메인 주도 설계

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

복잡한 복합 객체를 조립하는 일은 조립이 완료됐을 때 해당 객체가 하는 일과 가장 관련성이 적은 일이다.

그러나 애플리케이션에서 그와 같은 책임을 클라이언트 객체로 옮긴다면 문제가 훨씬 더 나빠진다. 클라이언트가 도메인 객체의 내부구조를 어느 정도 알고 있어야 하며, 도메인 객체의 각 구성요소의 관계에 적용되는 모든 불변식을 이행하려면 클라이언트에서 해당 객체의 규칙을 어느 정도 알아야 한다. 이렇게 되면 생성자를 호출하는 것만으로도 생성 중인 객체의 구상 클래스와 클라이언트가 결합된다. 클라이언트를 변경하지 않고는 도메인 객체의 구현을 변경할 수 없으며, 이로써 리팩토링이 더 힘들어진다.

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

자신의 책임이 다른 객체를 생성하는 것인 프로그램 요소를 FACTORY 라 한다. FACTORY 는 클라이언트의 요구사항과 내부 규칙을 충족하는 객체를 만든다.

FACTORY 는 복잡한 객체나 AGGREGATE 를 생성하는 데 필요한 지식을 캡슐화 한다.

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

전체 AGGREGATE 를 하나의 단위로 생성해서 그것의 불변식이 이행되게 하라.

Factory 생성 방법

  • Factory Method Pattern
  • Abstract Factory
  • Builder

Factory 의 올바른 위치

  • AGGREGATE ROOT 에 FACTORY METHOD 를 만들 수 있다.
    • AGGREGATE 의 무결성을 보장하는 책임을 ROOT 가 담당한다.
    • 모든 외부 클라이언트에게서 AGGREGATE 의 내부 구현을 감출 수 있다.
  • 생성된 객체를 소유하진 않지만 다른 객체를 만들어내는 것과 밀접한 관련이 있는 특정 객체에 FACTORY METHOD 를 둘 수 있다.
  • 독립형(standalone) FACTORY 를 만들 수 있다.
    • 전체 AGGREGATE 를 생성해서 루트에 대한 참조를 건네주며, 생성된 AGGREGATE 의 불변식이 지켜지도록 보장해준다.
  • 다형성을 활용한 FACTORY 를 만들 수 있다.
    • Factory Interface 는 Domain Layer 에 두며, 구현체는 Infrastructure 에 두어서 활용할 수 있다.
    • Ex. ItemOptionGroup 과 ItemOption 을 같이 생성하는 Factory 구현체를 Infrastructure 에 만든다.

생성자만으로 충분한 경우

  • 클래스가 타입인 경우. 클래스가 어떤 계층구조의 일부를 구성하지 않으며, 인터페이스를 구현하는 식으로 다형적으로 사용되지 않는 경우
  • 클라이언트가 STRATEGY 를 선택하는 한 방법으로서 구현체에 관심이 있는 경우
  • 클라이언트가 객체의 속성을 모두 이용할 수 있어서 클라이언트에게 노출된 생성자 내에서 객체 생성이 중첩되지 않는 경우
  • 생성자가 복잡하지 않은 경우
  • 공객 생성자가 FACTORY 와 동일한 규칙을 반드시 준수해야 하는 경우. 이때 해당 규칙은 생성된 객체의 모든 불변식을 충족하는 원자적인 연산이어야 한다.

인터페이스 설계

  • 각 연산은 원자적이어야 한다.
    • 복잡한 객체를 만들어내는 데 필요한 것들을 한 번에 FACTORY 로 전달해야 한다.
    • 생성이 실패해서 불변식이 충족되지 못하는 상황에서는 Exception 을 던지거나 Null 을 반환하는 등, 일관성을 지키기 위한 노력을 해야 한다.
    • FACTORY 에서 발생하는 실패에 대한 코딩 표준을 도입하는 것을 고려한다.
  • FACTORY 는 자신에게 전달된 인자와 결합될 것이다.
    • 인자가 단순히 생성물에 들어가는 것이라면 의존성이 적당한 상태다.
    • 그러나 인자를 끄집어내서 객체 생성 과정에 사용한다면 결합은 더 강해진다.
    • 가장 안전한 매개변수는 하위 계층에서 나오는 매개변수다.

References

  • 도메인 주도 설계 / Eric Evans 저 / 위키북스