开发者

Design: How to obtain precise logs when logging from "High-level" classes

Question

The following list of statements will quickly introduce my question:

  • An Interface called IValidator represents a contract for a validation process,
  • Some classes implement this interface with their own logic,
  • The Main method owns a List of IValidator and uses them all to perform validation,
  • The Main method needs to log an error if a validation goes wrong,
  • I don't want classes implementing IValidator to know about log at all (to be able to concentrate all log actions in Main),
  • I want the Main method to be able to log the reason of the validation failure.

The design question comes here: according to you what's the best way to have precise log about validation (开发者_如何学Ci.e. why did the validation fail) when classes implementing validation don't know about log ?

Here is some code illustrating my question:

public interface IValidator
{
    bool Validate(String toValidate);
}

public class VowelValidator : IValidator
{
    public bool Validate(string toValidate)
    {
        // .. Insert validation process here...
        return true;
    }
}

public class LenghtValidator : IValidator
{
    public bool Validate(string toValidate)
    {
        // .. Insert validation process here...
        return false;
    }
}

public class Manager
{
    public static void Main()
    {
        List<IValidator> validators = new List<IValidator>()
        {
            new VowelValidator(),
            new LenghtValidator()
        };

        foreach (var validator in validators)
        {
            if (!validator.Validate("FooBar"))
            {
                /*
                 * Handle log here.
                 * I'd like to log something like "failed because string is too long"
                 * or "failed because string does not contain vowels".
                 */
            }                    
        }
    }
}

Some possibilities

  • I could add a String GetValidationDescription() method to the IValidator and use it in Main to get a description of the validation that failed
    • But this means that every time I face that problem I'll have to add extra-methods only for log's sake. I'm not very happy with that.
  • I could log the actual type of the IValidator that failed (i.e. "Validation failed on LengthValidator") using GetType(). Then when I read the log I have to remember what that particular validator does and I can understand what went wrong.
    • This implies remembering / finding out what the validator does: no all information appears in the log.

Do you have other suggestions ? Are you aware of a common pattern for this kind of problem ?

Christophe.


Your current design for the validators is that they return true/false and do other information, but your requirement is to get some details about the failure, so you must change the interface or accept that the only thing you can log is that ValidtorXyz said "no".

Maintain a separation of concerns:

  1. The validator validates and reasonably report why validation fails
  2. The Logger logs information, so if it knew the the why it could log it, in some other scenario a UI might display the why

So logging is very clearly not the responsibility of the validator.

Adding a getValidationDescription() to the interface does not seem bad to me. It's quite legitimate for any object to describe itself - we do have toString() methods everywhere. There's nothing to say this is used specifically for logging.

However, a complex validator, for example a date validator, might fail for several reasons (eg. badly formatted input, month out of range ...) so I think you would do better to have as part of the result reasonForFailure.

One approach: create a return type object.

  class ValidationResult{
       boolean isValid;
       String validationDescription;
       String failureReason;
  }

another approach provide a failure callback

   validate(String input, IOnError callThisOnError);

where main provides:

   class OnError implements IOnError {
         void reportError(String input, String failureReason);
   }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜