tags:

views:

103

answers:

2

I have the concept of a "Rule" that I want to be able to process. As such, I created the Interface below:

  public interface IRule<T>
  {
    Boolean IsSatisfiedBy(T value);
    String GetViolationMessage(T value);
  }

I had planned on creating a series of "Rule" classes to represent the various rules currently supported by the system such as:

  public class MatchesPatternRule : IRule<String>
  {
    private readonly Regex _regex;
    private readonly String _pattern;

    public MatchesPatternRule(String pattern)
    {
      Verify.IsFalse(String.IsNullOrWhiteSpace(pattern));

      _regex = new Regex(pattern);
      _pattern = pattern;
    }

    public Boolean IsSatisfiedBy(String value)
    {
      return _regex.IsMatch(value);
    }

    public String GetViolationMessage(String value)
    {
      return String.Format(RuleMessage.MatchesPatternViolation, _pattern, value);
    }
  }

And then the rules would be consumed through a variety of extension methods such as:

public static ValidationContext<String> MatchesPattern(this ValidationContext<String> context, String pattern)
{
  context.AddRule(new MatchesPatternRule(pattern));
  return context;
}

However, I currently have plans for 20+ rules, and MatchesPatternRule class could be easily replaced by writting the extension method as:

public static ValidationContext<String> MatchesPattern(this ValidationContext<String> context, String pattern)
  where T : IComparable
{
  Verify.IsFalse(String.IsNullOrWhiteSpace(pattern));

  Regex regex = new Regex(pattern);
  context.AddRule(value => regex.IsMatch(value), value => String.Format(RuleMessage.MatchesPatternViolation, _pattern, value));
  return context;
}

Curious as to what approach is better and why? Both are easily testible and ultimately achieve the end result. Any insight would be greatly appreciated!

UPDATE

Based on the feedback from Tom, I think I have opted to go with a middle-ground approach. I am going to create a static class to hold the extension methods for each "rule". This will ensure that any given rule is easy to find, and will keep my code organized but also reduce the amount of code overall.

  public static class MatchesPatternRule
  {
    public static ValidationContext<String> MatchesPattern(this ValidationContext<String> context, String pattern)
    {
      return MatchesPattern<T>(context, pattern, pattern, RegexOptions.None);
    }

    public static ValidationContext<String> MatchesPattern(this ValidationContext<String> context, String pattern, String friendlyPattern)
    {
      return MatchesPattern<T>(context, pattern, friendlyPattern, RegexOptions.None);
    }

    public static ValidationContext<String> MatchesPattern(this ValidationContext<String> context, String pattern, RegexOptions options)
    {
      return MatchesPattern<T>(context, pattern, pattern, options);
    }

    public static ValidationContext<String> MatchesPattern(this ValidationContext<String> context, String pattern, String friendlyPattern, RegexOptions options)
    {
      Verify.IsFalse(String.IsNullOrWhiteSpace(pattern));

      Regex regex = new Regex(pattern);
      context.AddRule(value => regex.IsMatch(value), value => String.Format(RuleMessage.MatchesPatternViolation, _pattern, value));

      return context;
    }
  }
+1  A: 

I'm not a C# user, but in Ruby and Scala, one has similar choices. Having a class that adheres to a particular interface in something like this context seems to have a similar use as a closure, albeit with a bit more boilerplate. As they are going for the same goal technically, surely the question then becomes which is best socially for the context.

Are the people who are supposed to be writing these rules smart enough to get their head around closures? If not, the class-based solution might be a better one to use. If I don my Java-programmer-trying-to-understand-all-this-C#-fanciness hat on, the class-based solution may be a bit easier than having to learn all this weird functional stuff - I know the weird functional stuff, but I can imagine myself not knowing it! Only you can decide what is best for the people who are going to be writing the rules. If you are the only person who is having to write the rules, go crazy! Pick whatever you prefer aesthetically.

How about documentation and meta-data? Future extensibility? What if you need to add extra fields to the rules? Is it easier to document the class-based solution over the closure-based one? If you have to find and change a rule, which one will make it easier to do so?

Tom Morris
+1  A: 

Why can't you have both? For simple rules you could use closures. The ValidationContext.AddRule could convert your closures to rules. Or maybe an extension method that converts a closure to rule.

palto