设计需求满意度结构

时间:2011-04-05 15:10:00

标签: c#

我正在尝试将“需求”类型系统实现到程序中。在我的头脑中看起来很简单,但实际上使它足够抽象以使其变得有用并证明比预期更困难。

这是我想要做的......

enum Condition {
 Not, Exists, Exceeds
}

abstract class Requirement { 
  // base class
  Condition Condition { get; set; }
}

class ScoreRequirement : Requirement {
  // a specific 'score' is required
}
class TraitRequirement : Requirement {
  // a specific 'trait' is required
}
class SatisfyingObject {
  // this is the class that has to satisfy the requirements
  IDictionary<Trait, int> Traits { get; set; }
}

如果我知道在代码时间必须满足的确切事情,这很简单。但目标是让人们以后增加需求。还有其他类型派生自Requirement

所以要求可能会像这样......

var obj = new Item { 
 Requirements = new List<Requirement> {
   new ScoreRequirement { Trait = "One", Score = 2, Condition = Condition.Exceeds }
 }
}

所以这个概念看起来很简单。你会召唤一个物体..

var satisfying = // get the satisfying object;

if( satisfying.Satisfies( obj.Requirements ) )
 return true;

我遇到的问题实际上是如何对Satisfies方法进行编码 - 具体而言我不确定如何将其与Condition参数相关联。我希望人们能够设置一些相当通用的“要求”,但这背后的逻辑对我来说非常混乱。由于在设计时不知道要求,我不能真正硬编码任何一个。

有什么建议吗?

2 个答案:

答案 0 :(得分:1)

如果这不是一个学习项目而不是我强烈建议您使用已经为此构建的东西:

  1. EntLib Validation Block
  2. Fluent Validation
  3. 任何建立在System.ComponentModel.DataAnnotations
  4. 之上的东西

    如果您这样做是一个简单的学习项目 ,那么您可以采取两种基本方法:

    1. 基于反思
    2. 基于代表
    3. 在这两者中,基于委托的实现起来要简单得多,但不够灵活。我已多次实现此模式,概念很简单。这是关于你可以得到的最基本的概念。

      public interface IRuleDefinition
      {
          String PropertyName { get; }
          String Message { get; }
      }
      
      public class ValidationRule<T>: IRuleDefinition
      {
          public String PropertyName { get; private set; }
          public String Message { get; private set; }
      
          private Func<T, Boolean> _isValidDelegate;
      
          public ValidationRule(Func<T, Boolean> isValidDelegate, String propertyName, String message)
          {
              PropertyName = propertyName;
              Message = message;
              _isValidDelegate = isValidDelegate;
          }
      
          public Boolean IsValid(T objToValidate)
          {
              return _isValidDelegate(objToValidate);
          }
      }
      
      public class Validator<T>
      {
          private List<ValidationRule<T>> _validationRules = new List<ValidationRule<T>>();
      
          public void AddRule(Func<T, Boolean> isValidDelegate, String propertyName = null, String message = null)
          {
              _validationRules.Add(new ValidationRule<T>(isValidDelegate, propertyName, message));
          }
      
          public Boolean IsValid(T objToValidate)
          {
              return _validationRules.Any(vr => vr.IsValid(objToValidate));
          }
      
          public IEnumerable<IRuleDefinition> GetViolations(T objToValidate)
          {
              return _validationRules
                   .Where(vr => !vr.IsValid(objToValidate))
                   .Cast<IRuleDefinition>();
          }
      }
      

      您可以在以下代码中使用它:

      var myObj = new MyObject{ Name = "Josh", Age = 29 };
      
      var myObjValidator = new Validator<MyObject>();
      
      myObjValidator.AddRule(
          obj => !String.IsNullOrWhitespace(obj.Name), 
          "Name", "Name is required!");
      
      myObjValidator.AddRule(
          obj => obj.Age < 99,
          "Age", "Age must be less than 99");
      
      myObjValidator.AddRule(
          obj => obj.Name == "Logan" && obj.Age < 29,
          message: "RUN!!!");
      
      if(!myObjValidator.IsValid(myObj))
      {
          foreach(var violation in myObjValidator.GetViolations(myObj))
              Console.WriteLine("Property: {0}, Message: {1}", 
                  violation.PropertyName, violation.Message);
      }
      

      现在,这一切都来自内存,因此可能是一些可能是编码/编译器错误,但希望你能得到一般的想法。

      同样,如果这不是学习项目,then don't reinvent the wheel unless you are planning to learn more about wheels :)

答案 1 :(得分:0)

我建议确定指定要求所需的最小范围,并从中开始,以了解设计的复杂程度。如果您发现即使是最小范围也会导致很多复杂性,或者如果您甚至无法掌握最小范围,那么您可能希望研究一种更灵活的方法,例如托管脚本用于表达约束的语言。有许多可用的库来支持这一点,它们的支持/维护成本比你创建的更便宜,并且自己进化以努力提供一种“简单”的设置约束的方式。

如果可以,请保持简单,但如果确实需要复杂,请尝试找到已经构建并作为基础测试的内容,以减轻复杂性的负担。