6

I'm writing a postcode validation library, so that I can call a helper method

var result = Postcode.IsValid(postcode, country)

To that end I need to have 'classes' that represent supported countries and know how to validate each. At present I have an interface thus:

public interface IPostcode {
    bool IsValid(string postcode);
}

and I have to have classes for each country, e.g.

public class USA : IPostcode {
  public bool IsValid(string postcode) {
     // ... validate here
  }

The helper method selects the relevant IPostcode based on the country code.

The issue is that it feels wrong to have to instantiate classes that have no state or properties, just methods which would be far better if they were static. But of course static classes can't have interfaces. Is there a better pattern for this?

5

I don't think there is anything wrong with having classes without state. As long as the classes have different behavior (different postcode validation logic) they are justified.

You could kind-of achieve the same thing with static methods and using a delegate signature rather than an interface (since the interface is only a single function signature anyway) but I think using classes are more natural and straightforward.

  • 2
    I agree. I assume the "state" of the class is implicit anyway in the OP's scenario, and is backed by some sort of postcode database. But even if it wasn't and the validation was purely algorithmic, it is perfectly legitimate to use stateless classes that operate only on their method parameters - the strategy pattern being a prime example. Static classes are best left for very general and invariant functionality - you wouldn't want to instantiate or pass around an Adder object every time you want to add two numbers together, for example. – Steve Jan 30 '18 at 14:09
5

The point of an interface is to allow multiple implementations to expose the same functionality contract.

Although your implementation of IPostCode may have no state, and thus you are tempted to enforce that by making the method static. I may have an implementation which hits a database, and needs the connection string or whatever.

You can still wrap a static method if you must

USA : IPostcode
{
    private static bool isValid(string postcode) {...}
    public bool IsValid(string postcode)
    {
        return isValid(postcode);
    }
}

Or inject a Func which can be declared statically elsewhere

USA : IPostcode
{
    public USA(Func<string, bool> postcodeValidator) {...}
    public bool IsValid(string postcode)
    {
        return postcodeValidator(postcode);
    }
}

But don't throw away the IPostCode interface, as it has numerous benefits, allowing other implementations to be used, especially in testing. Where you may well want to replace your standard validation with a dummy

MockCountry : IPostcode
{
    public bool IsValid(string postcode)
    {
         return true;
    }
}

Which would be next to impossible to do with just statics

0

The following suggestion should only be used if the individual country validators do not eg fetch data from a database at runtime, ie only access immutable data.

Assuming they do, the simplest solution here is to ditch the idea of polymorphism via interface implementations and to switch to using a dictionary of functions instead:

public static class Postcode
{
    private static readonly Dictionary<string, Func<string, bool>> Validators = 
        new Dictionary<string, Func<string, bool>>
        {
            ["USA"] : USAPostcode.IsValid,
            ["UK"] : UKPostcode.IsValid,
            ...
        };

    public static bool IsValid(string postcode, string country) =>
        Validators.TryGetValue(country, out var validator) 
        ? validator(postcode) 
        : throw new ArgumentException("No such country", nameof(country));
}

Static classes do not support interfaces, but static methods are ideally designed for use with Func<> delegates. So "plumb them together" that way instead.

Just remember: do not use static methods for accessing or modifying state, eg fetching data from a database at runtime. So only use this pattern if the set of validators, and their rules, are immutable.

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.