5

I have a StringValidator. A StringValidator is either a Regex or a string pattern using '*' wildcards. I want the StringValidator.StringIsValid() to perform one action or a different one, depending on which overloaded constructor was used. I can think of several ways to do this, but I have no idea of the best way.

Note that this is a simplified example, and I know I can convert strings to Regexs. That's not the type of solution I'm looking for.

For example, I could set a flag in each constructor to indicate which one was called. Or, I could condition the behavior on which variable was null.

I'm not sure the overall thrust of what I'm trying to do is even a good idea.

11

What you described here is a textbook example of a strategy pattern. You define an interface for validation, implement as many different implementations as you need, and then instantiate the implementation you need based on what you decide is needed.

The following is tested code.

The Strategy Pattern part:

public interface IValidationStrategy
{
    bool Validate(string pStringToValidate);
}

public class RegexValidator : IValidationStrategy
{
    private Regex regEx;

    public RegexValidator(Regex regEx)
    {
        this.regEx = regEx;
    }

    public bool Validate(string stringToValidate)
    {
        return regEx.IsMatch(stringToValidate);
    }
}

public class WildCardValidator : IValidationStrategy
{
    private string wildCard;

    public WildCardValidator(string wildCard)
    {
        this.wildCard = wildCard;
    }

    public bool Validate(string pStringToValidate)
    {
        //http://stackoverflow.com/questions/30299671/matching-strings-with-wildcard
        string regex = Regex.Escape(wildCard).Replace("\\*", ".*");
        return Regex.IsMatch(pStringToValidate, "^" + regex + "$");
    }
}

Accepting a Dependency Injection (IValidationStrategy) and using a nested builder class to construct the different strategy implementations in an immutable way:

public class StringValidator
{
    private IValidationStrategy validationStrategy;

    //Dependendency Injection constructor
    public StringValidator(IValidationStrategy validationStrategy)
    {
        this.validationStrategy = validationStrategy;
    }

    public bool Validate(string stringToValidate)
    {
        return validationStrategy.Validate(stringToValidate);
    }

    public class Builder
    {
        public StringValidator Regex(string regex)
        {
            return new StringValidator(new RegexValidator(new Regex(regex)));
        }

        public StringValidator WildCard(string wildCard)
        {
            return new StringValidator(new WildCardValidator(wildCard));
        }
    }
}

Two different ways to test:

class Program
{
    static void Main(string[] args)
    {
        Console.Out.WriteLine(
            "IsValid: {0}",
            new StringValidator.Builder()
                .Regex(@"\d+")
                .Validate("55")
        );

        Console.Out.WriteLine(
            "IsValid: {0}",
            new StringValidator.Builder()
                .WildCard("*")
                .Validate("Whatever string to be validated")
        );

        // Or, if you hate using nameless temporary objects

        Console.Out.WriteLine();

        StringValidator.Builder stringValidatorBuilder = new StringValidator.Builder();

        string regex = @"\d+";
        StringValidator regValidator = stringValidatorBuilder.Regex(regex);
        bool isValid = regValidator.Validate("55");
        Console.Out.WriteLine("IsValid: {0}", isValid);

        string wildCard = "*";
        StringValidator wildCardValidator = stringValidatorBuilder.WildCard(wildCard);
        isValid = wildCardValidator.Validate("Whatever string to be validated");
        Console.Out.WriteLine("IsValid: {0}", isValid);
    }
}

Outputs:

IsValid: True
IsValid: True

IsValid: True
IsValid: True
  • I like this. What would help would be a few lines showing it being used. – candied_orange Oct 27 '16 at 7:16
  • I have a version of this that actually works. Mind if I edit the answer? – candied_orange Oct 27 '16 at 8:28
  • By all means, go ahead – Vladimir Stokic Oct 27 '16 at 11:46
  • Done. I've tweaked the method of construction a bit. – candied_orange Oct 27 '16 at 17:04
  • Submitted this to Code Review – candied_orange Oct 27 '16 at 17:55
0

It is not a good idea.

Your classes should have a single clear responsibility, and one validator that does both regex validation and string wildcard is two. They should instead have a shared interface, and perhaps a nice helper method that builds the correct one depending on input.

Separate classes makes them easier to test, easier to reuse, easier to maintain.

  • 3
    Oh, I don't know. If there's a clear way to distinguish between the regex and wildcard patterns, it could simply be a single method. No need for method overloads. The notion of "responsibility" is a bit fluid anyway; you don't create four endpoints on a service just because you need Create, Read, Update and Delete methods. Counter-example: Date/Time formatting strings in C#. There are many more ways to do those than just two. – Robert Harvey Oct 27 '16 at 3:10
  • You don't create four endpoints on a service for Create, Read, Update and Delete methods, but separate classes that would execute those functionalities and only be invoked by the service might be a good idea. Of course, if the task to be done is trivial, then there is no need for overengineering. – Vladimir Stokic Oct 28 '16 at 8:37
0

I don't see a problem with that.

Can it not be seen as a mere implementation detail?

You can have your StringValidator constructor overloads dispatch their argument to various protected properties:

public class StringValidator
{
    protected void Require(string strategy, object validation)
    {
        if (validation == null)
        {
            throw new ArgumentNullException("validation", string.Concat(strategy, " cannot be null");
        }
    }

    public StringValidator(Regex regex)
    {
        Require("regex", regex);
        RegexValidation = regex;
    }

    public StringValidator(string wildcard)
    {
        Require("wildcard", wildcard);
        WildcardValidation = wildcard;
    }

    // Derived validators, if any, will just override this, by:
    // if (NewValidation != null) {
    // ...
    // }
    // else
    //     return base.Validate(input);
    protected virtual bool Validate(string input)
    {
        if (WildcardValidation != null)
        { // Wildcard matching strategy
          // return ...
        }
        else
        { // Regex matching strategy
          // return ...
        }
        // Proper constructors should guarantee there is exactly one validation strategy ready
    }

    public bool IsValid(string input)
    {
        return Validate(input);
    }

    protected string WildcardValidation { get; private set; }

    protected Regex RegexValidation { get; private set; }

    // Etc
}

I think you can get away with this only because, fundamentally, that sort of StringValidator public interface/contract with clients, is coincidentally, rather minimal;

In essence, that's simply,

bool IsValid(string input)

But surely, though, I would not use this implementation approach I just sketched for things that get more involved than that after construction time, and/or for a richer public interface (be it with or without mutable state).

'Hope this helps.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.