1

今天我在想“告诉!不要问!” 并尝试使用此代码。

接口:

interface IValidationContext
{
  void AddMessage(string text);   
  bool IsValid { set; }
}

interface IValidation
{
  void ValidateInput(Input input, IValidationContext context); 
  void ValidateOutput(Output output, IValidationContext context); 
}

interface ICalculator
{
  Output Calculate(Input input);
}

实现:

class CalculationService
{
  private readonly ICalulator _calculator;
  private readonly IValidation _validation;

  public CalculationService(ICalculator calculator, IValidation validation)
  {
    _calculator = calculator;
    _validation = validation;
  }

  public Output Calculate(Input input)
  {
     var context = new CalculationContext();
     _validation.ValidateInput(input, context);

     if (context.IsValid)
     {
        var output = _calculator.Calculate(input);
        _validation.ValidateOutput(output, context);
        return output
     }
     return null;
  }
}

class CalculationContext : IValidationContext
{
  public CalculationContext()
  {
    Messages = new List<string>();
  }

  public IList<string> Messages { get; private set; }

  public void AddMessage(string text)
  {
    Messages.Add(text);
  }

  public bool IsValid { set; get; }
}

我知道并不总是可能符合设计原则。但最后我坚持使用这段代码,我问一个对象:

 if (context.IsValid)
 {
   var output = _calculator.Calculate(input);
   _validation.ValidateOutput(output, context);
 }

是否有可能解决它是否实用

编辑1:
如果我修改我的IValidationContext并重命名它:

interface ICalculationContext
{
   void AddMessage(string text);   
   Output Calculate(ICalculator calculator, Input input);
   bool IsValid { set; }
}

不需要询问上下文:

public Output Calculate(Input input)
{
  _validation.ValidateInput(input, context);        
  var output = context.Calculate(_calculator, input);
  _validation.ValidateOutput(output, context);
  return output;
}

现在上下文负责根据其内部状态调用计算。……感觉不对……

编辑2:
我读了一篇关于“告诉!不要问!”的小文章。它指出:询问一个对象的内部状态,然后根据该状态告诉该对象一些事情,这将违反“告诉!不要问!” 但是可以告诉另一个对象一些事情。这适用于这里吗?

顺便提一句。ValidateInput为和引入一个布尔值有效结果ValidateOutput。可以将代码更改为此,这很好,没有人被“询问”一些东西:

public Output Calculate(Input input)
{
  var isValid = _validation.ValidateInput(input, context);

  if (isValid)
  {
    var output = _calculator.Calculate(input);
    _validation.ValidateOutput(output, context);
    return output
  }
  return null;
}
4

1 回答 1

3

这条线是问题的根源

var context = new CalculationContext();

您应该将其注入CalculationContext到,CalculationService以便您可以在课堂外审问它。该Calculate方法告诉验证器验证输入和输出。 在这种情况下询问将是这样的代码:

public Output Calculate(Input input)
{
   var validator = _context.Validator;
   if (validator.IsInputValid(input)) {
       // ... snip ...
   }
}

在这里,我们询问验证器特定输入是否有效,而不是告诉它验证某些内容。此外,我们限制自己使用对象IsValid上的 getter 。IValidationContext这是一个有点模糊的情况,因为访问_context.Validator可以被视为违反了德墨忒耳法则,但是这个属性是在接口中定义的,并且只返回一个接口,所以我们不耦合到这些类的任何具体实现。

这是一个建议,假设对接口进行以下修改

interface IValidationContext
{
    void AddMessage(string text); 
    IValidation Validator { get; }
    bool IsValid { get; }
}

interface IValidation
{
    void ValidateInput(Input input); 
    void ValidateOutput(Output output); 
}

interface ICalculator
{
    Output Calculate(Input input);
}


class CalculationService
{
    private readonly ICalulator _calculator;
    private readonly IValidationContext _context;

    public CalculationService(ICalculator calculator, IValidationContext context)
    {
      _calculator = calculator;
      _context = context;
    }

    public Output Calculate(Input input)
    {
       _context.Validator.ValidateInput(input);

       if (_context.IsValid)
       {
          var output = _calculator.Calculate(input);
          _context.Validator.ValidateOutput(output);

          return output;
       }
       return null;
    }
}
于 2012-08-21T18:41:40.143 回答