이 질문은 핵심적인 디자인 질문입니다. 질문을 설명하기 위해 Java/Java EE 예제를 사용합니다.디자인 : 도메인 개체와 서비스 개체 사이의 선이 분명하지 않은 경우
지속성을 위해 JPA를 사용하고 서비스 계층을 위해 EJB를 사용하여 빌드 된 웹 메일 응용 프로그램을 생각해보십시오. 다음과 같이 EJB에 서비스 메소드가 있다고 가정 해 보겠습니다.
public void incomingMail(String destination, Message message) {
Mailbox mb = findMailBox(destination); // who cares how this works
mb.addMessage(message);
}
이것은 합리적인 비즈니스 방법입니다. 아마도 사서함 개체는 계속 첨부되고 변경 내용을 데이터베이스에 원활하게 저장합니다. 결국 그것은 투명한 지속성에 대한 약속입니다.
사서함 개체는이 방법을 것이다 :
여기public void addMessage(Message message) {
messages.add(message);
}
그것이 복잡해진다 어디 - 우리가 다른 사서함 유형을 갖고 싶어 가정합니다. 발신자에게 자동 응답하는 AutoRespondingMailbox와 수신 된 각 전자 메일과 함께 헬프 데스크 티켓을 자동으로 열리는 HelpDeskMailbox가 있다고 가정 해보십시오.
AutoRespondingMailbox이 방법이 사서함, 확장하는 것입니다 수행하는 자연적인 것 :
public void addMessage(Message message) {
String response = getAutoResponse();
// do something magic here to send the response automatically
}
문제는 우리의 Maibox 객체와 그 서브 클래스는, "도메인 개체"(그리고이 예에 있다는입니다 JPA 엔티티). Hibernate 녀석 (그리고 많은 다른 사람들)은 비 의존적 도메인 모델, 즉 컨테이너/런타임 제공 서비스에 의존하지 않는 도메인 모델을 선전합니다. 이러한 모델의 문제는 AutoRespndingMailbox.addMessage() 메소드가 예를 들어 JavaMail에 액세스 할 수 없기 때문에 이메일을 보낼 수 없다는 것입니다.
HelpDeskMailbox에서 HelpDesk 시스템과 통신하기 위해 WebServices 또는 JNDI 삽입에 액세스 할 수 없기 때문에 똑같은 문제가 발생합니다.
은 그래서 당신은 다음과 같이 서비스 계층에서이 기능을 넣을 수밖에 :
public void incomingMail(String destination, Message message) {
Mailbox mb = findMailBox(destination); // who cares how this works
if (mb instanceof AutoRespondingMailbox) {
String response = ((AutoRespondingMailbox)mb).getAutoResponse();
// now we can access the container services to send the mail
} else if (mb instanceof HelpDeskMailbox) {
// ...
} else {
mb.addMessage(message);
}
}
가 그런 식으로 instanceof를 사용할 수있는 것은 문제의 첫 징후이다. Mailbox의 하위 클래스를 만들 때마다이 서비스 클래스를 수정하면 문제의 또 다른 징후입니다.
이러한 상황을 처리하는 방법에 대한 모범 사례가 있습니까? 어떤 사람들은 Mailbox 객체가 컨테이너 서비스에 액세스해야한다고 말하고 있지만, 이는 퍼지 (fudging)로 수행 할 수 있습니다.하지만 컨테이너가 엔티티를 제외한 모든 곳에서 의존성 주입을 제공하므로 명확하게 JPA의 용도와 싸우고 있습니다 이는 예상 된 유스 케이스가 아니라는 것을 의미합니다.
그래서 대신 무엇을해야합니까? 우리의 봉사 방법을 고치고 다형성을 포기 하시겠습니까? 우리의 객체는 자동적으로 C 스타일 구조체로 강등되고 OO의 이점 대부분을 잃어버린다.
Hibernate 팀은 비즈니스 로직을 도메인 계층과 서비스 계층으로 분리하고 컨테이너에 의존하지 않는 모든 로직을 도메인 엔티티에 넣고에 의존하는 모든 로직을 배치해야한다고 말합니다 서비스 레이어에 컨테이너. 만약 누군가가 다형성을 완전히 포기하고 instanceof 및 기타 불쾌감에 의존하지 않고서 어떻게해야하는지에 대한 예를 나에게 줄 수 있다면 받아 들일 수 있습니다.
내 질문의 의도를 놓친 것 같아요. 예제의 특성을 잊어 버리고 Entity의 일부 하위 클래스가 일부 컨테이너 제공 서비스에 의존하는 동작을 필요로한다고 가정합니다. – TTar
동의합니다. 문제는 도메인 개체가 더 이상 단순한 데이터 소유자가 아니지만 이제는 지속성에 영향을주는 동작을 연결 한 것입니다. 개인적으로 이것은 서비스 수준에서 처리되어야하는 것으로 느껴집니다. –
도메인 객체가 단순한 데이터 보유자 인 경우 내 도메인 객체가 구조체가 아닌지? 데이터와 행동이 객체로 결합 된 객체 지향 디자인의 정의가 아닌가? – TTar