7

일련의 규칙에 따라 업데이트해야하는 필드가있는 간단한 Entity Framework 지원 도메인 오브젝트가있는 시스템을 설계 중입니다.이를 구현하고 싶습니다. 규칙은 점진적으로 (민첩한 스타일로), EF를 사용할 때 각 규칙을 도메인 객체에 넣는 것에 대해 회의적입니다. 그러나 "절차 코드"를 작성하고 빈혈 도메인 모델을 사용하는 것을 피하고 싶습니다. 이 모든 것도 테스트 할 수 있어야합니다. 예를 들어비즈니스 로직을 규칙의 형태로 사용하여 빈혈 도메인 모델을 피하는 방법

는, 객체는 다음과 같습니다

class Employee { 
private string Name; 
private float Salary; 
private float PensionPot; 
private bool _pension; 
private bool _eligibleForPension; 

} 

내가 같은 규칙을 구축 할 필요가 "급여보다 높은 10 만이고 _eligibleForPension는 경우는 false 다음 _eligibleForPension 설정 참으로"_pension는 다음에 해당하는 경우 "와 _eligibleForPension을 true로 설정하십시오. "

약 20 개의 규칙이 있으며 Employee 클래스 또는 EmployeeRules 클래스와 같은 구현 여부에 대한 조언이 필요합니다. 내 첫 번째 생각은 각 규칙에 대해 "Rule"을 상속 한 별도의 클래스를 만든 다음 Employee 클래스에 각 규칙을 적용하는 것이 었습니다. 방문자 패턴을 사용했지만 모든 필드를 규칙에 적용해야합니다. 잘못된 생각. 각 규칙을 Employee 클래스에 두는 것도 괜찮은 것 같지 않습니다. 이것이 어떻게 구현 될까요?

둘째 관심사는 실제 Employees가 DB에 백업 된 Entity Framework 엔터티이므로 이러한 "Entities"에 논리를 추가하는 것이 행복하지 않다는 것입니다. 특히 각 규칙을 단위 테스트하기 위해 개체를 조롱해야하는 경우 더욱 그렇습니다. 동일한 객체에 대해 테스트 할 규칙이 있다면 어떻게 조롱 할 수 있습니까?

나는 AutoMapper를 사용하여 규칙을 적용하기 전에 좀 더 간단한 도메인 개체로 변환하려고했지만 이후 필드에 대한 업데이트를 직접 관리해야합니다. 이것에 대한 조언도 있나?

답변

7

한 가지 방법은 규칙 내부 클래스를 Employee으로 만드는 것입니다. 이 방법의 이점은 필드가 비공개로 유지 될 수 있다는 것입니다. 또한, 규칙의 호출이 필요한 때 항상 호출되는 것을 보장, Employee 클래스 자체적으로 적용 할 수 있습니다 : 여기

class Employee 
{ 
    string id; 
    string name; 
    float salary; 
    float pensionPot; 
    bool pension; 
    bool eligibleForPension; 

    public void ChangeSalary(float salary) 
    { 
     this.salary = salary; 
     ApplyRules(); 
    } 

    public void MakeEligibleForPension() 
    { 
     this.eligibleForPension = true; 
     ApplyRules(); // may or may not be needed 
    } 

    void ApplyRules() 
    { 
     rules.ForEach(rule => rule.Apply(this)); 
    } 

    readonly static List<IEmployeeRule> rules; 

    static Employee() 
    { 
     rules = new List<IEmployeeRule> 
     { 
      new SalaryBasedPensionEligibilityRule() 
     }; 
    } 

    interface IEmployeeRule 
    { 
     void Apply(Employee employee); 
    } 

    class SalaryBasedPensionEligibilityRule : IEmployeeRule 
    { 
     public void Apply(Employee employee) 
     { 
      if (employee.salary > 100000 && !employee.eligibleForPension) 
      { 
       employee.MakeEligibleForPension(); 
      } 
     } 
    } 
} 

하나의 문제는 Employee 클래스의 모든 규칙 구현을 포함한다는 것이다. 이는 규칙이 근로자 연금과 관련된 비즈니스 논리를 구체화하고 함께 속해 있기 때문에 큰 문제는 아닙니다.

+0

도움이 될 것이다 장난. 내 원하는 디자인 인 private 필드를 예로 들었지만 EF는 public 속성을 가지고 있으므로 Employees 클래스에 직접 액세스하면 내부 클래스를 사용할 필요가 없습니다. 누군가가 EF 부품을 포함하여 질문에 대답 할 수 있기를 희망하며 질문을 공개적으로 남겨 둘 것입니다. 감사! – PCurd

+0

약간 수정 된 접근법을 사용하여 시스템의 데모 모델을 만들었습니다. 내부 클래스로는 규칙이 없으며 작동하고 잘 느낍니다. 나는이 시스템에 대해 공개 된 필드가 끔찍한 범죄가 아니라는 것을 안다.하지만 내면의 수업을 통해 다시 시도해 볼 수도있다. 당신의 도움을 주셔서 감사합니다. – PCurd

4

비즈니스 규칙은 일반적으로 흥미로운 주제입니다. 집계/엔티티 불변 조건과 비즈니스 규칙의 차이가있을 수 있습니다. 비즈니스 규칙에 외부 데이터가 필요할 수 있으며 집계/엔티티를 변경하는 규칙에 동의하지 않습니다.

규칙에 대한 사양 패턴을 고려해야합니다. 규칙은 기본적으로 정렬 여부에 관계없이 구분이 잘못되었는지 여부를 반환해야합니다.

예제에서 SalaryBasedPensionEligibilityRule은 eulerfx에서 사용하는 것으로이 필요할 수 있습니다. 이 규칙은 실제로 엔티티의 유효성을 검사하지 않기 때문에 작업과 비슷해 보입니다.

그래서 규칙은 결정 메커니즘이며 작업은 상태를 변경하는 것이 좋습니다.

당신은 아마 당신이 상태를 노출하고 싶지 않을 수도 있기 때문에 여기에 조언을 엔티티를 물어보고 싶은 말했다되고 그건 :

public class Employee 
{ 
    float salary; 
    bool eligibleForPension; 

    public bool QualifiesForPension(float pensionThreshold) 
    { 
     return salary > pensionThreshold && !eligibleForPension; 
    } 

    public void MakeEligibleForPension() 
    { 
     eligibleForPension = true; 
    } 
} 

이 명령/쿼리 분리 아이디어 스틱.

당신이 당신의 ORM 객체에서 직접 구축하고 싶지 않거나 할 수없는 경우, 모든 행동이 그 확인입니다 포함 ---하지만 확실히는 할 것 같은이 보인다 :

+0

재미있는 접근 방식으로 "객체와 논리를 유지하라"는 더 좋은 예를 제시합니다. Employee 객체에 구현 된 각 비즈니스 로직이 끝나면 "이 규칙의 조건을 충족합니까? 그러면이 업데이트를 트리거합니까?"라는 질문에 대한 책임이있는 다른 객체가있을 것입니다. 이 작업이 빠르게 복잡 해지는 것을 알 수있을뿐만 아니라 Employee 객체에 연결된 모든 로직을 유지할 수 있습니다. Employee 객체에 대한 많은 조건과 업데이트가 필요한지 여부에 따라 달라질 수 있습니다. 업데이트를 마샬링하는 다른 객체가 어떻게 생겼는지 예를 들려 줄 수 있습니까? – PCurd

+0

"업데이트를 마샬링하는 다른 객체가 어떻게 생겼는지 예제를 줄 수 있습니까?" --- 나는 정말로 * 이것을 이해하지 못한다. --- 당신의 질문을 다시 말해 줄 수 있습니까? –

+0

죄송합니다! 어딘가에 "if employee.QualifiesForPension (100000) then employee.MakeEligibleForPension();"함수가 있어야합니다. 이 직원과 직원의 관계는 어떻게 될 것인가? 그것은 별도의 클래스가 될 것이며, 그렇다면 어떤 모습일까요? – PCurd