today i was thinking about "tell! don't ask!" and experimenting with this code.
interfaces:
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);
}
implementations:
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; }
}
i know it is not always possible conform a design-principle. but in the end i stuck with this code where i'm asking an object:
if (context.IsValid)
{
var output = _calculator.Calculate(input);
_validation.ValidateOutput(output, context);
}
is it possible solve it whether it is practical or not?
edit 1:
if i modify my IValidationContext
and rename it:
interface ICalculationContext
{
void AddMessage(string text);
Output Calculate(ICalculator calculator, Input input);
bool IsValid { set; }
}
the context don't need to be askd:
public Output Calculate(Input input)
{
_validation.ValidateInput(input, context);
var output = context.Calculate(_calculator, input);
_validation.ValidateOutput(output, context);
return output;
}
now the context is responsible to call calculation based on its internal state. ...it dont feel right...
edit 2:
i read a small article about "tell! don't ask!" and it states that:
asking an object for its internal state and then tell that object something depending on that state, would violate "tell! don't ask!" but it's ok to tell another object something.
does this apply here?
btw. introducing an boolean-isvalid-result for ValidateInput
and ValidateOutput
.
could change the code to this, which is nice and nobody gets "asked" something:
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;
}