도메인 객체는 우리가 해결하고자 하는 핵심 비즈니스 로직이 반영되는 곳입니다. 특히 도메인 객체에서 자기 자신의 책임을 충분히 다하지 않으면 그 로직들은 자연스럽게 Service 영역 및 외부 영역에서 해당 책임 넘겨받아 구현하게 됩니다. 본인의 책임을 다하는 도메인 객체를 만들고 다른 레이어와 어떻게 메시지를 주고받는지 포스팅을 진행하겠습니다.
전체 이름, 전체 주소를 가져오기 위해서는 Member 객체에서 기능을 구현해야 합니다. 즉 Member의 책임이 늘어나는 것입니다. 그뿐만이 아닙니다. Name, Address는 많은 도메인 객체에서 사용되는 객체이므로 중복 코드의 증가됩니다. 아래 코드는 Embedded을 활용한 코드입니다.
privatevoidverifyUsed(){ if (used) thrownew CouponAlreadyUseException(); }
privatevoidverifyExpiration(){ if (LocalDate.now().isAfter(getExpirationDate())) thrownew CouponExpireException(); } }
쿠폰에 만료 여부, 쿠폰이 사용 가능 여부, 쿠폰의 사용 등의 메서드는 어느 객체에서 제공해야 할까요? 당연히도 쿠폰 객체 자신입니다.
출처 : 객체지향의 사실과 오해 (정말 정말 추천드리고 싶은 도서입니다.)
객체는 충분히 '협력적’이어야 한다. 객체는 다른 객체의 요청에 충실히 귀 기울이고 다른 객체에게 적극적으로 도움을 요청할 정도로 열린 마음을 지녀야 한다. 객체는 다른 객체의 명령에 복종하는 것이 아니라 요청에 응답할 뿐이다. 어떤 방식으로 응답할지는 객체 스스로 판단하고 결장한다. 심지어 요청에 응할지 여부도 객체 스스로 결정할 수 있다.
단순하게 getter, setter 메서드만 제공한다면 이는 협력적인 관계가 아닙니다. 그저 복종하는 관계에 지나지 않습니다. 또 요청에 응답할지 자체도 객체 스스로가 결절할 수 있게 객체의 자율성을 보장해야 합니다. use() 메서드 요청이 오더라도 쿠폰 객체는 해당 요청이 알맞지 않다고 판단하면 그 요청을 무시하고 예외를 발생시킵니다. 이렇듯 객체의 자율성이 있어야 합니다.
setter를 사용하게 되면 해당 객체는 복종하는(수동적인) 관계를 갖게 됩니다.(순수하게 값을 바인딩 하는 코드만 있는 setter를 의미) setUse(true) 메서드는 그저 used 필드를 true 변경하는 외부 객체에 복종하는 메서드 그입니다. 쿠폰 객체 스스로가 자율성을 갖고 해당 메시지에 응답을 할지의 여부도 판단해야 외부 객체와 능동적인 관계를 갖게 됩니다.
또한 복종하는 관계에서는 쿠폰 사용 로직을 만들기 위해서 내가 객체의 세부적인 사항을 다 알고 있어야 합니다. 쿠폰 만료일, 만료 여부, 기타 등등 수많은 세부사항을 다 알고 검사를 하고 나서 비로소 use() 메서드를 호출하게 됩니다. 이것은 본인의 책임을 다하고 있지 않아 외부 객체에게 해당 책임이 넘어가는 경우입니다.
지금까지 설명드린 대부분의 경우는 도메인 객체에 국한 되지 않습니다. 모든 객체에 적용되는 설명입니다. 도메인 객체는 모든 레이어에서 사용하는 아주 중요한 객체이므로 여기서부터 올바른 책임을 제공해 주고 있지 않으면 모든 곳에서 힘들어지기 때문에 도메인 객체 가이드에 작성했습니다.