상태
오늘 저녁 나는 준 대답 에 StackOverflow에 대한 질문을.
질문:
기존 객체의 편집은 저장소 계층 또는 서비스에서 수행해야합니까?
예를 들어 부채가있는 사용자가있는 경우. 나는 그의 빚을 바꾸고 싶다. 객체를 가져 와서 편집하고 저장하여 BuyingService와 같은 UserRepository 또는 서비스에서해야합니까?
내 대답 :
객체를 동일한 객체로 변경하는 책임은 그대로두고 리포지토리를 사용하여이 객체를 검색해야합니다.
상황 예 :
class User {
private int debt; // debt in cents
private string name;
// getters
public void makePayment(int cents){
debt -= cents;
}
}
class UserRepository {
public User GetUserByName(string name){
// Get appropriate user from database
}
}
내가받은 의견 :
비즈니스 로직은 실제로 서비스에 있어야합니다. 모델에 없습니다.
인터넷은 무엇을 말합니까?
따라서 서비스 레이어를 실제로 (의식적으로) 사용한 적이 없기 때문에 검색이 가능합니다. 서비스 계층 패턴과 작업 단위 패턴을 읽기 시작했지만 지금까지 서비스 계층을 사용해야한다고 확신 할 수 없습니다.
Anemic Domain Model의 안티 패턴에 대한 Martin Fowler 의이 기사 를 예로 들어 보겠습니다 .
도메인 공간에는 명사의 이름을 따서 명명 된 객체가 많이 있으며, 이러한 객체는 실제 도메인 모델의 풍부한 관계 및 구조와 연결됩니다. 캐치는 당신이 행동을 볼 때오고, 당신은 이러한 객체에 행동이 거의 없다는 것을 깨닫고 게터와 세터의 가방 이상을 만들지 않습니다. 실제로 이러한 모델에는 도메인 논리를 도메인 개체에 넣지 말아야한다는 디자인 규칙이 있습니다. 대신 모든 도메인 논리를 캡처하는 일련의 서비스 개체가 있습니다. 이러한 서비스는 도메인 모델 위에 있으며 도메인 모델을 데이터에 사용합니다.
(...) 도메인 개체에 있어야하는 논리는 유효성 검사, 계산, 비즈니스 규칙 등 도메인 논리입니다.
나에게 이것은 정확히 상황에 관한 것 같았습니다. 나는 그 클래스 안에 메소드를 도입하여 객체의 데이터 조작을 옹호했습니다. 그러나 이것은 어느 쪽이든 주어져야한다는 것을 알고 있으며 아마도 리포지토리를 사용하여 이러한 메소드를 호출하는 방법과 더 관련이 있습니다.
또한이 기사 (아래 참조)에서 서비스 계층은 실제 작업 집약적 계층보다 기본 모델에 작업을 위임 하는 외관으로 간주된다는 느낌이 들었습니다 .
응용 프로그램 계층 [서비스 계층의 이름] : 소프트웨어가 수행해야하는 작업을 정의하고 표현 도메인 개체가 문제를 해결하도록 지시합니다. 이 계층이 담당하는 작업은 비즈니스에 의미가 있거나 다른 시스템의 응용 프로그램 계층과 상호 작용하는 데 필요합니다. 이 층은 얇게 유지됩니다. 여기에는 비즈니스 규칙이나 지식이 포함되지 않지만 작업을 조정하고 다음 계층에서 도메인 개체의 공동 작업에 대한 작업 만 위임합니다. 비즈니스 상황을 나타내는 상태는 없지만 사용자 또는 프로그램의 작업 진행률을 나타내는 상태는 가질 수 있습니다.
서비스 인터페이스. 서비스는 모든 인바운드 메시지가 전송되는 서비스 인터페이스를 제공합니다. 서비스 인터페이스는 애플리케이션에서 구현 된 비즈니스 로직 (일반적으로 비즈니스 계층의 로직)을 잠재적 인 소비자에게 노출시키는 외관으로 생각할 수 있습니다.
그리고 여기 :
서비스 계층에는 응용 프로그램이나 비즈니스 논리가 없어야하며 주로 몇 가지 문제에 중점을 두어야합니다. Business Layer 통화를 래핑하고 고객이 이해할 수있는 공용 언어로 도메인을 번역하며 서버와 요청하는 클라이언트 간의 통신 매체를 처리해야합니다.
이것은 서비스 계층에 대해 이야기 하는 다른 리소스 와는 심각하게 대조됩니다 .
서비스 계층은 동일한 트랜잭션에 속하는 조치의 작업 단위 인 메소드가있는 클래스로 구성되어야합니다.
또는 내가 이미 연결 한 질문에 대한 두 번째 답변 :
어느 시점에서 응용 프로그램은 비즈니스 로직을 원할 것입니다. 또한 요청이 악의적이거나 성능이 저하되지 않도록 입력의 유효성을 검사 할 수 있습니다. 이 논리는 서비스 계층에 속합니다.
"해결책"?
이 답변 의 지침에 따라 서비스 계층을 사용하는 다음과 같은 접근법을 생각해 냈습니다.
class UserController : Controller {
private UserService _userService;
public UserController(UserService userService){
_userService = userService;
}
public ActionResult MakeHimPay(string username, int amount) {
_userService.MakeHimPay(username, amount);
return RedirectToAction("ShowUserOverview");
}
public ActionResult ShowUserOverview() {
return View();
}
}
class UserService {
private IUserRepository _userRepository;
public UserService(IUserRepository userRepository) {
_userRepository = userRepository;
}
public void MakeHimPay(username, amount) {
_userRepository.GetUserByName(username).makePayment(amount);
}
}
class UserRepository {
public User GetUserByName(string name){
// Get appropriate user from database
}
}
class User {
private int debt; // debt in cents
private string name;
// getters
public void makePayment(int cents){
debt -= cents;
}
}
결론
컨트롤러의 코드가 서비스 계층으로 옮겨졌습니다. 그러나 이것은 원래의 대답과 관련이없는 것처럼 보입니다.
나는 디자인 패턴이 지침이 아니라 가능할 때마다 구현되어야 할 규칙이 아니라는 것을 알고 있습니다. 그러나 나는 서비스 계층에 대한 결정적인 설명과 그것을 어떻게 고려해야하는지 찾지 못했다.
단순히 컨트롤러에서 로직을 추출하여 대신 서비스에 넣는 수단입니까?
컨트롤러와 도메인간에 계약을 맺어야합니까?
도메인과 서비스 계층 사이에 계층이 있어야합니까?
그리고 마지막으로 : 원래 의견에 따름
비즈니스 로직은 실제로 서비스에 있어야합니다. 모델에 없습니다.
이 올바른지?
- 모델 대신 서비스에서 비즈니스 로직을 어떻게 소개합니까?