program tip

봄과 빈혈 도메인 모델

radiobox 2020. 11. 22. 19:19
반응형

봄과 빈혈 도메인 모델


그래서 저는 분명히 Spring / Hibernate 스택 객체를 다음과 같이 패턴 화하는 경향이 있음을 알았습니다.

  • Foo 컨트롤러가 "FooService"를 호출합니다.
  • FooService는 FooRepository.getById () 메서드를 호출하여 Foos를 가져옵니다.
  • FooRepository는 Foo 객체를로드하기 위해 Hibernate 호출을합니다.
  • FooService는 Foos와 일부 상호 작용을 수행합니다. 트랜잭션에서 함께 수행해야하는 작업을 처리하기 위해 관련 TransactionalFooService를 사용할 수 있습니다.
  • FooService는 FooRepository에 Foos를 저장하도록 요청합니다.

여기서 문제는 Foos가 실제 논리가 없다는 것입니다. 예를 들어, Foo가 만료 될 때마다 이메일을 보내야하는 경우 Foo.expire ()를 호출하지 않습니다. FooService.expireFoo (fooId)에 대한 호출이 있습니다. 그 이유는 다음과 같습니다.

  • Foo에서 다른 서비스와 개체를 얻는 것은 성가신 일입니다. Spring 빈이 아니며 Hibernate에 의해로드되었습니다.
  • Foo가 트랜잭션 방식으로 여러 작업을 수행하도록하는 것은 성가신 일입니다.
  • Foo가 자신을 저장할시기를 선택할 책임이 있는지 여부를 결정하기는 어렵습니다. foo.setName ()을 호출하면 foo가 변경 사항을 유지해야합니까? foo.save ()를 호출 할 때까지 기다려야합니까? foo.save ()가 FooRepository.save (this)를 호출해야합니까?

따라서 이러한 종류의 이유로 내 Spring 도메인 객체는 기본적으로 일부 유효성 검사 논리를 사용하여 영광스러운 구조체 인 경향이 있습니다. 괜찮을지도 몰라요. 웹 서비스는 절차 코드로 괜찮을 것입니다. 새로운 기능이 작성됨에 따라 동일한 이전 개체를 새로운 방식으로 처리하는 새로운 서비스를 만드는 것이 허용됩니다.

그러나 나는 이런 종류의 디자인에서 벗어나고 싶습니다. 그리고 다른 Spring 사용이 그것에 대해 무엇을하는지 궁금합니다. 로드 타임 위빙과 같은 멋진 트릭으로이 문제를 해결합니까 (내가별로 편하지 않음)? 다른 트릭이 있습니까? 절차가 괜찮다고 생각하십니까?


AOP를 사용하여 Spring이 Hibernate 인스턴스화 된 인스턴스에 서비스를 주입하도록 할 수 있습니다. 인터셉터를 사용하여 Hibernate가 동일한 작업을 수행하도록 할 수도 있습니다.

참조 http://www.jblewitt.com/blog/?p=129를

"Foo가 트랜잭션 방식으로 여러 작업을 수행하도록하는 것은 성가신 일입니다."와 관련하여 서비스 구현이 트랜잭션에 대해 알고 /주의를 기울일 것으로 예상하고 도메인 모델 내에서 서비스 인터페이스를 사용하고 있다면 현재는 그렇지 않을 것입니다. 너무 짜증나.

도메인 모델을 저장해야하는시기를 결정하는 것은 그것이 무엇인지, 그리고 그것을 가지고 무엇을하는지에 달려 있다고 생각합니다.

FWIW 나는 똑같은 종류의 빈혈 구조를 만드는 경향이 있지만 거기에 이르렀습니다. 이제 더 합리적인 방법으로 할 수 있다는 것을 알고 있습니다.


응용 프로그램이 절차 적 코딩 원칙을 중심으로 설계된 것 같습니다. 이것만으로도 당신이하려는 객체 지향 프로그래밍을 방해 할 것입니다.

Foo가 제어하는 ​​동작이 없을 수도 있습니다. 비즈니스 로직이 최소 인 경우 도메인 모델 패턴을 사용 하지 않는 것도 허용됩니다 . 트랜잭션 스크립트 패턴은 때로는 의미가 있습니다.

그 논리가 커지기 시작할 때 문제가 발생합니다. 트랜잭션 스크립트를 도메인 모델로 리팩토링하는 것이 가장 쉬운 것은 아니지만 확실히 가장 어려운 것은 아닙니다. Foo를 둘러싼 많은 논리가 있다면 도메인 모델 패턴으로 이동하는 것이 좋습니다. 캡슐화의 이점은 무슨 일이 일어나고 있고 누가 무엇에 관여 하는지를 매우 쉽게 이해할 수있게 해줍니다.

원하는 경우 Foo.Expire()Foo 클래스에 OnExpiration. 에서 foo.OnExpiration += FooService.ExpireFoo(foo.Id)사용하는 팩토리를 통해 객체 생성에 연결하십시오 FooRepository.

먼저 생각하세요. 그건 아주 지금은 ... 모든 권리 장소에서 이미 가능성.

행운을 빕니다!


문제를 해결할 간단한 리팩토링 패턴이 있다고 생각합니다.

  1. 저장소에 서비스를 삽입하십시오.
  2. Foo를 반환하기 전에 FooService를 설정하십시오.
  3. 이제 FooController가 FooRepository에서 적절한 Foo를 요청하도록합니다.
  4. 이제 Foo에서 원하는 메서드를 호출하십시오. 자체적으로 구현할 수없는 경우 FooService에서 적절한 메서드를 호출하도록합니다.
  5. 이제 Foo에서 "bucket bridge"메서드를 호출하는 것을 통해 FooService에 대한 모든 호출을 제거합니다 (매개 변수를 서비스에 전달하기 만 함).
  6. 이제부터는 메소드를 추가 할 때마다 Foo에 추가하십시오.
  7. 성능상의 이유로 정말로 필요할 때만 서비스에 항목을 추가하십시오 . 항상 그렇듯이 이러한 메서드는 모델 개체를 통해 호출되어야합니다.

이를 통해 더 풍부한 도메인 모델로 발전 할 수 있습니다. 또한 모든 DB 종속 코드가 FooService 구현에 남아 있고 비즈니스 로직을 FooService에서 Foo로 마이그레이션하는 데 도움이되기 때문에 단일 책임 원칙을 보존합니다. 백엔드를 다른 DB 또는 인 메모리 또는 모의 (테스트 용)로 전환하려는 경우 FooService 레이어 만 변경할 필요가 없습니다.

^ 나는 FooService가 주어진 Foo와 속성 X를 공유하는 가장 최근의 Foo를 선택하는 것과 같이 ORM에서 수행하기에는 너무 느린 DB 호출을 수행한다고 가정하고 있습니다. 그것이 내가 본 대부분의 방법입니다.


대신에:

class Controller{
    public Response getBestStudentForSchool( Request req ){
        Student bestStudent = StudentService.findBestPupilForSchool( req.getParam( "schlId" ).asInt() );
        ...
    }
}

다음과 같이 이동할 것입니다.

class Controller{
    public Response getBestStudentForSchool( Request req ){
        School school = repo.get( School.class, req.getParam( "schlId" ).asInt() ); 
        Student bestStudent = school.getBestStudent();
        ...
    }
}

Which I will hope you will agree already seems richer. Now you are making another database call, but if you keep the School cached in session the penalty is neglible. I'm afraid that any truly OOP model will be less efficient than the anemic model you are using, but the reduction of bugs through code clarity should be worth it. As always, YMMV.


I recommend you the book Use Case Driven Object Modeling with UML by Doug Rosenberg and Matt Stephens. It talks about the ICONIX process a software development methodology that also talks about anemic domain model. It's also a topic developed by Martin Fowler in it's web site https://www.martinfowler.com/bliki/AnemicDomainModel.html . But how do we achieve when using Spring Framework and/or Spring Boot is what I'm also try to figure out.

참고URL : https://stackoverflow.com/questions/1304245/spring-and-the-anemic-domain-model

반응형