Как решить, что последнее "спросить" в сложном расчете соответствует "говорите! Не спрашивайте!"?

Сегодня я думал о "скажи! не спрашивай!" и экспериментируя с этим кодом.

интерфейсы:

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:
я прочитал небольшую статью о "скажи! не спрашивай!" и в нем говорится, что: запрос объекта на его внутреннее состояние, а затем указание этому объекту чего-либо, зависящего от этого состояния, приведет к нарушению "говори! не спрашивай!" но можно сказать что-то другому объекту. это применимо здесь?

Кстати. введя логический-isvalid-результат для 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;
}

1 ответ

Решение

Эта строка является источником проблемы

var context = new CalculationContext();

Вы должны вводить CalculationContext в CalculationService так что вы можете допросить его за пределами класса. Calculate Метод говорит валидатору проверять ввод и вывод. Запрос в этом контексте будет выглядеть так:

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

Здесь мы спрашиваем валидатор, является ли конкретный вход действительным, вместо того, чтобы сказать ему что-то проверить. Кроме того, мы ограничиваемся работой с IsValid добытчик на 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;
    }
}
Другие вопросы по тегам