1

그래서 저는 리포지토리 모델에 대해 배웠습니다. 리포지토리가 많은 복잡한 논리를 수행하지 않을 것으로 예상됩니다. 그러나 나는 또한 비즈니스 로직의 대부분이 내 Controllers 안에 있으면 안된다는 것을 읽었다. 그래서 어디에 넣을까요?리포지토리 및 서비스, MVC 모델

일부 샘플 응용 프로그램을 살펴본 결과 Services이라는 또 다른 복잡한 로직을 사용하는 레이어가있는 것으로 보입니다. 그렇다면이 요소는 MVC 패턴에 어떤 영향을 줍니까?

내 리포지토리에 액세스하기 위해 서비스를 구축 한 다음 내 컨트롤러가 서비스에 액세스하기를 원합니까? 이렇게?

interface IMembershipService 
{ 
bool ValidateUser(string username, string password); 
MembershipCreateStatus Create(string username, string password); 
} 
interface IMembershipRepository 
{ 
MembershipCreateStatus Create(string username, string password); 
} 

class MembershipRepository : IMembershipRepository 
{ 
public MembershipRepository(ISession session) 
{ 
    **// this is where I am confused...** 
} 
} 
class MembershipService : IMembershipService 
{ 
private readonly IMembershipRepository membershipRepository; 
public MembershipService(IMembershipRepository membershipRepository) 
{ 
    this.membershipRepository = membershipRepository; 
} 

public bool ValidateUser(string username, string password) 
{ 
    // validation logic 
} 
public MembershipCreateStatus Create(string username, string password) 
{ 
    return membershipRepository.Create(username, password); 
} 
} 

class MembershipController : Controller 
{ 
private readonly IMembershipService membershipService; 

public MembershipController(IMembershipService membershipService) 
{ 
    this.membershipService = membershipService 
} 
} 

내 코드의 표시된 부분은 나를 혼란스럽게합니다. 내가 읽은 모든 것은 내 ISession을 내 저장소에 주입해야한다고 말했습니다. 즉, 내 서비스에 ISession을 주입 할 수 없다는 것을 의미하므로 내 서비스에서 데이터베이스 액세스를 어떻게 수행합니까? 프로세스가 여기에 해당하는지 이해가되지 않습니다.

ValidateUser을 내 IMembershipRepository에 넣었을 때 '나쁘다'고 들었습니다. 그러나 IMembershipRepository은 데이터베이스 액세스가있는 곳입니다. 그게 의도 야, 그렇지? 데이터베이스 액세스를 최소화하려면? 하지만 다른 논리를 넣을 수 없다면 요점은 무엇입니까?

누군가가이 문제에 대해 조명하고 더 실용적 일 수있는 예를 보여줄 수 있습니까?

나는 Fluent nHibernate, ASP.NET MVC 3.0Castle.Windsor을 사용하고 있습니다.

내가 대신

class MembershipService 
{ 
private readonly IMembershipRepository membershipRepository; 

public MembershipService(ISession session) 
{ 
    membershipRepository = new MembershipRepository(session); 
} 
} 

그리고 결코 내 컨트롤러보다는 Repositories에 직접 액세스 권한을 부여 ... 그런 짓을해야 하는가?

답변

4

내가 읽은 모든 내용은 제 저장소를 제 저장소에 주입해야한다고 말했습니다.

맞습니다. 데이터 액세스가 이루어지기 때문에 저장소 생성자에 세션을 삽입해야합니다.

즉, 서비스에 ISession을 주입 할 수 없다는 의미입니다. 그렇다면 내 서비스에서 데이터베이스 액세스를 어떻게 수행합니까?

서비스에서 데이터베이스 액세스를 수행하지 마십시오. 이 서비스는 생성자에 삽입 된 하나 이상의 리포지토리에 의존하며 각각의 메서드를 사용합니다. 서비스는 데이터베이스에 직접 쿼리하지 않습니다. 요약하자면 그래서

:

  • 저장소는 모델에 간단한 CRUD 작업이 포함되어 있습니다. 여기서 데이터 액세스가 수행됩니다. 이 데이터 액세스는 반드시 데이터베이스를 의미하지는 않습니다. 사용중인 기본 저장소에 따라 다릅니다. 예를 들어 클라우드에서 일부 원격 서비스를 호출하여 데이터 액세스를 수행 할 수 있습니다.
  • 서비스는 하나 이상의 리포지토리를 사용하여 비즈니스 운영을 구현합니다. 이 비즈니스 운영은 리포지토리에 대한 하나 이상의 CRUD 작업에 따라 달라질 수 있습니다. 서비스는 데이터베이스의 존재를 알지 않아야합니다.
  • 컨트롤러는 서비스를 사용하여 비즈니스 작업을 호출합니다.
  • 서로 다른 계층 간의 결합을 줄이기 위해 인터페이스를 사용하여 작업을 추상화합니다. 이 안티 패턴과 같은 서비스를 만들기
+0

그래서 ..내 'Service'에'Session'을 삽입하고 서비스 내에 새로이 인스턴스화 된'Repository' 객체로 전달해야합니까? 나는 이것이 IoC와 어떻게 관련이 있는지에 관해서는 잃어버린 것 같다. 나는 당신이 볼 수 있고, 내가 더 잘 이해하는지 나에게 말할 수 있다면, 나의 지위의 바닥에 약간을 더했다. – Ciel

+0

@Stacey, 아니요, 당신은 서비스에'Session '을 삽입하지 않습니다. 저장소에 서비스를 주입합니다. 그리고 당신은'ISession'을 저장소에 삽입합니다. 그래서 컨트롤러를 생성하기 위해서는 서비스가 필요하고, 서비스를 만들기 위해서는 저장소가 필요하고 저장소를 만들기 위해서는'Session '이 필요합니다. 이 배관 작업은 사용중인 DI 프레임 워크에 의해 수행됩니다. –

+0

첨부 된 예제가 잘못 되었다면 더 정확한 예제를 보여줄 수 있습니까? _dependency Injection_이 나를 위해이 일을해야한다고 생각했기 때문에 실제로'new' 키워드로 인스턴스를 초기화해야한다면 내 저장소를 인스턴스화하는 방법을 이해하지 못합니다. – Ciel

1
interface IMembershipService 
{ 
bool ValidateUser(string username, string password); 
MembershipCreateStatus Create(string username, string password); 
} 

.

이와 같은 서비스에는 몇 개의 책임이 있습니까? 얼마나 많은 이유가 바뀔 수 있습니까?

또한 논리를 서비스에 넣으면 빈혈 도메인으로 끝납니다. 결국 트랜잭션 스크립트 스타일의 절차 코드가 완성됩니다. 그리고 나는 이것이 반드시 나쁜 것임을 말하는 것이 아닙니다.

아마도 리치 도메인 모델은 적합하지 않지만이 두 가지 사이에는 의식적인 결정이 있어야하며이 다중 책임 서비스는 어느 경우에도 적합하지 않습니다.

public MembershipCreateStatus Create(string username, string password) 
{ 
    return membershipRepository.Create(username, password); 
} 

점은 무엇인가 :

이것은 거대한 붉은 깃발을해야 하는가? 레이어를위한 레이어? 서비스는 아무런 가치가 없으며 목적이 없습니다.

많은 개념이 없습니다.

첫째, 객체를 생성하는 공장을 사용하는 것이 좋습니다 :

public interface IMembershipFactory { 
    MembershipCreateStatus Create(string username, string password); 
} 

공장을 인스턴스를 구축하거나 엔티티 객체의 수명을 시작으로가는 모든 로직을 캡슐화 할 수 있습니다.

둘째, 저장소는 개체 컬렉션의 추상화입니다. 팩터 리를 사용하여 개체를 만든 다음 개체를 개체 컬렉션에 추가합니다.

var result = _membershipFactory.Create("user", "pw"); 
if (result.Failed); // do stuff 
_membershipRepository.Add(status.NewMembership); // assumes your status includes the newly created object 

는 마지막으로 엔터티에 대해 수행 할 수있는 모든 작업하는 방법을 포함 MyEntityService 클래스는 내 감각에 몹시 불쾌 보인다.

대신 각 작업을 단일 Service 클래스의 메서드가 아닌 개별 Command 클래스로 모델링하여보다 명확하고 좋은 캡처 인 텐트로 만들려고합니다.

public class ChangePasswordCommand { 
    public Guid MembershipId { get; set; } 
    public string CurrentPassword { get; set; } 
    public string NewPassword { get; set; } 
} 

그런 일이이 명령이 전송 될 때 실제로 뭔가를 가지고, 그래서 우리는 핸들러 사용

public interface IHandle<TMessageType> { 
    void Execute(TMessageType message); 
} 

public class ChangePasswordCommandHandler : IHandle<ChangePasswordCommand> { 

    public ChangePasswordCommandHandler(
     IMembershipRepository repo 
    ) 
     {} 

    public void Execute(ChangePasswordCommand command) { 
     var membership = repo.Get(command.MembershipId); 
     membership.ChangePassword(command.NewPassword); 
    } 
} 

명령은 우리의 IoC 컨테이너와 인터페이스하는 간단한 클래스를 사용하여 발송됩니다.

이렇게하면 획일적 인 서비스 클래스를 피하고 프로젝트 구조와 논리 위치를 훨씬 명확하게 만들 수 있습니다.

+0

이 방법은 전에 보지 못했던 방법입니다. 이 일에 대해 어떤 방식으로 문서를 가지고 있습니까? IoC 컨테이너에서 이걸 연결하는 방법 처럼요? – Ciel

+0

end-to-end 예제는 많은 작은 조각을 포함하고 있습니다. 아마도 많은 품질의 샘플을 보지 못했을 것입니다. 대신에 저장소 및 서비스의 일반적인 훼손으로 과도하게 단순화 된 샘플을 볼 수 있습니다. 내가 도착한 많은 것들은 CQRS와 DDD의 입주자뿐 아니라 단방향 메시징 (ala NServiceBus)이있는 분산 형 솔루션을 설계하고 있습니다. –

+0

나는 나중에이 부분으로 돌아가서 명령 처리기 디스패처와 IoC와 관련된 다른 부분에 대한 정보를 추가하려고합니다. –