15

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?

Quango
  • 271
  • 1
  • 2
  • 8
  • 1
    https://codeburst.io/static-classes-are-evil-or-make-your-dependencies-explicit-af3e73bd29dd – Vadim Samokhin Jan 30 '18 at 12:14
  • Why not just leave it at what you call the helper method and put a switch statement in it that takes country for an argument? I see no purpose for an interface here. Just do your regex match logic in the different cases for country (which I imagine would be an enum). – Martin Maat Feb 09 '22 at 11:58

4 Answers4

11

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

Ewan
  • 70,664
  • 5
  • 76
  • 161
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.

JacquesB
  • 57,310
  • 21
  • 127
  • 176
  • 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
1

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.

David Arno
  • 38,972
  • 9
  • 88
  • 121
1

Additional answer for future readers of my question: there is now a preview feature in C# 10 for Static abstract members in interfaces

This means in my original problem, I could have defined the interface thus:

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

So an implementation might look like this:

public class UKPostcode : IPostcode
{
    public static bool IsValid(string postcode)
    {
        // todo: validate the value here
        
    }
}

Even better, you can now implement methods in interfaces in C# 10 so that the helper class Postcode is redundant:

public interface IPostcode
{
    public static abstract bool IsValid(string postcode);

    public static bool IsValid(string countryCode, string postcde)
    {
        switch (countryCode)
        {
            case "GB": return UKPostcode.IsValid(postcde);

            default:
                throw new NotSupportedException();
        }
    }
}
Quango
  • 271
  • 1
  • 2
  • 8