"당신은 계층 구조에서 유효성 검사가 어디에 있는지 묻는 또 다른 질문이 아닌가?" 글쎄요, 그러나 이것은 주제에 대해 조금 다른 생각이 될 수 있기를 바랍니다.
유효성 검사는 다양한 형식을 취하고 상황에 따라 다르며 아키텍처의 각 수준에 따라 다릅니다. 이것이 포스트의 기초입니다-각 계층에서 어떤 유형의 검증이 수행되어야하는지 식별하는 데 도움이됩니다. 또한 권한 검사가 속하는 곳이 자주 제기됩니다.
예제 시나리오는 케이터링 비즈니스를위한 애플리케이션에서 비롯됩니다. 주간에는 운전자가 트럭을 현장에서 현장으로 가져가는 동안 누적 된 초과 현금이 사무실로 들어올 수 있습니다. 이 응용 프로그램을 통해 사용자는 운전자 ID와 금액을 수집하여 '현금 하락'을 기록 할 수 있습니다. 관련 레이어를 설명하기위한 일부 스켈레톤 코드는 다음과 같습니다.
public class CashDropApi // This is in the Service Facade Layer
{
[WebInvoke(Method = "POST")]
public void AddCashDrop(NewCashDropContract contract)
{
// 1
Service.AddCashDrop(contract.Amount, contract.DriverId);
}
}
public class CashDropService // This is the Application Service in the Domain Layer
{
public void AddCashDrop(Decimal amount, Int32 driverId)
{
// 2
CommandBus.Send(new AddCashDropCommand(amount, driverId));
}
}
internal class AddCashDropCommand // This is a command object in Domain Layer
{
public AddCashDropCommand(Decimal amount, Int32 driverId)
{
// 3
Amount = amount;
DriverId = driverId;
}
public Decimal Amount { get; private set; }
public Int32 DriverId { get; private set; }
}
internal class AddCashDropCommandHandler : IHandle<AddCashDropCommand>
{
internal ICashDropFactory Factory { get; set; } // Set by IoC container
internal ICashDropRepository CashDrops { get; set; } // Set by IoC container
internal IEmployeeRepository Employees { get; set; } // Set by IoC container
public void Handle(AddCashDropCommand command)
{
// 4
var driver = Employees.GetById(command.DriverId);
// 5
var authorizedBy = CurrentUser as Employee;
// 6
var cashDrop = Factory.CreateCashDrop(command.Amount, driver, authorizedBy);
// 7
CashDrops.Add(cashDrop);
}
}
public class CashDropFactory
{
public CashDrop CreateCashDrop(Decimal amount, Employee driver, Employee authorizedBy)
{
// 8
return new CashDrop(amount, driver, authorizedBy, DateTime.Now);
}
}
public class CashDrop // The domain object (entity)
{
public CashDrop(Decimal amount, Employee driver, Employee authorizedBy, DateTime at)
{
// 9
...
}
}
public class CashDropRepository // The implementation is in the Data Access Layer
{
public void Add(CashDrop item)
{
// 10
...
}
}
코드에서 유효성 검사가 수행 된 위치를 10 곳 표시했습니다. 내 질문은 다음과 같은 비즈니스 규칙 (길이, 범위, 형식, 유형 등에 대한 표준 검사와 함께)에서 수행 할 수있는 검사입니다.
- 현금 인출 액은 0보다 커야합니다.
- 현금 인출에는 유효한 운전자가 있어야합니다.
- 현재 사용자는 현금 인출을 추가 할 권한이 있어야합니다 (현재 사용자는 드라이버가 아님).
당신의 생각, 당신이이 시나리오를 가지고 있거나 어떻게 접근 할 것인지, 그리고 선택 이유를 공유하십시오.
CashDropAmount
사용하는 대신 값 객체를 사용하여 값 객체 를 활용할 수 있다고 생각합니다 Decimal
. 드라이버가 존재하는지 여부를 확인하는 것은 명령 핸들러에서 수행되며 권한 부여 규칙도 마찬가지입니다. Approver approver = approverService.findById(employeeId)
직원이 승인자 역할을 수행하지 않는 경우 던지는 위치 와 같은 작업을 수행하여 무료로 승인을받을 수 있습니다. Approver
엔티티가 아닌 가치 객체 일뿐입니다. 팩토리를 제거하거나 대신 AR에서 팩토리 메소드를 사용할 수도 있습니다 cashDrop = driver.dropCash(...)
.