여기에 문제의 원인 : Rule
의 구현 인
var nameRule = new Rule<CreditCard>(c => !string.IsNullOrEmpty(c.Name));
var dateRule = new Rule<CreditCard>(c => c.Date > DateTime.
:이 경우에는 더 이상의 규칙 유형을 필요로하지 않을 구성 요소 (비즈니스 규칙 구현)를 런타임 데이터 (CreditCard
인스턴스의 등록 정보 (런타임에만 알 수 있음)로 변환하는 반면 injecting application components with runtime data is an anti-pattern.
대신, 구성 요소는 무, 그리고, 당신이 (factories are a code smell 때문에) 공장 내부와 같은 구성 요소를 만들 필요 방지 IRule
추상화의 공개 API를 통해 런타임 데이터를 전달하여, 당신이 설명 된대로 이러한 유지 보수 문제를 방지한다 귀하의 질문에.
또한
public interface IBusinessRule<TEntity>
{
IEnumerable<string> Validate(TEntity entity);
}
내가 너무 Validate
변경 참고 :이 정확히 그것이 확인을 정의하는 형태 보증 된 비즈니스 규칙 구현을 만들 수 있기 때문에
@InBetween는 IRule
추상화 제네릭을 만드는 방법에 대한 매우 좋은 설명을했다 그것은 부울을 반환하지 않고 오히려 (0 이상) 유효성 검사 오류의 모음을 반환합니다. 이렇게하면 시스템이 요청 처리를 중단 한 이유를보다 명확하게 전달할 수 있습니다. 다음과 같이
구현 보일 수 있습니다 :
클래스 CreditCardNameNotEmpty : IBusinessRule { 공공는 IEnumerable 유효성 검사 (크레딧 카드 엔티티) { 경우 (문자열입니다.IsNullOrWhiteSpace (entity.Name) yield returns "신용 카드 이름을 입력해야합니다."; } }
생성자에서 런타임 데이터를 이동함으로써 이제는 자신의 종속성을 포함하는 응용 프로그램 구성 요소를보다 쉽게 만들 수 있습니다. 예 :
클래스 CreditCardDateIsValid : IBusinessRule { private readonly ILogger logger; public CreditCardDateIsValid (ILogger 로거) { this.logger; 이 반환 된 컬렉션을 반복하는 소비자를 강제 때문에 우리가 비즈니스 규칙 유효성 검사를 필요 구성 요소로의 IEnumerable<IBusinessRule<T>>
, 이것은 할 좋은되지 않을 것 주입 수 있지만 }
public IEnumerable<string> Validate(CreditCard entity) {
// etc
}
}
하는 많은 코드 중복을 일으킬 것입니다. 따라서 대신 소비자의 추상화를 숨기고 자신의 필요에보다 중점을 둔 추상화를 제시하고자합니다. 다음과 같이
public interface IValidator<T>
{
// Throws a ValidationException in case of a validation error.
void Validate(T instance);
}
우리는 쉽게 구현할 수 있습니다 : 예를 들어 지금
class MyPaymentProcess : IPaymentProcessor
{
private readonly IValidator<CreditCard> creditCardValidator;
public MyPaymentProcess(IValidator<CreditCard> creditCardValidator) {
this.creditCardValidator = creditCardValidator;
}
public void MakePayment(CreditCard card)
{
this.creditCardValidator.Validate(card);
// continue the payment
}
}
주 그 MakePayment
방법 :
public class Validator<T> : IValidator<T>
{
private readonly IEnumerable<IBusinessRule<T>> rules;
public Validator(IEnumerable<IBusinessRule<T>> rules) {
if (rules == null) throw new ArgumentNullException(nameof(rules));
this.rules = rules;
}
public void Validate(T instance) {
if (instance == null) throw new ArgumentNullException(nameof(instance));
var errorMessages = rules.Select(rule => rule.Validate(instance)).ToArray();
if (errorMessages.Any()) throw new ValidationException(errorMessages);
}
}
을이 다음에 지불 프로세서를 단순화 할 수있게 해준다 더 이상 bool
을 반환하지 않습니다. 이것은 작업이 약속 한 작업을 수행 할 수없는 경우 (이 경우 지급) 예외가 발생해야하기 때문입니다. 부울 값을 반환하면 오류 코드가 반환됩니다. 이는 이전에 남긴 연습입니다.
아마도 Validate()뿐만 아니라 bool Validate (CreditCard 카드) 규칙과의 인터페이스가 필요할 수도 있습니다. – Evk
예, 훨씬 편리해야하지만이 코드는 타인의 것으로서 작업으로 사용하고 수정할 수는 없습니다. –
어쨌든 생성자에 이름과 다른 데이터를 전달하는 것이 좋지 않을 경우 전체 CreditCard를 하나의 양식 또는 다른 규칙으로 전달해야합니다. – Evk