Imagine the following scenario – you have created some validators for your models: Foo, Bar and Xyz.
public interface IValidator { bool Validate(object model); } // Validator for Foo class public class FooValidator : IValidator { public bool Validate(object model) { // ... } } // Validator for Bar class public class BarValidator : IValidator { public bool Validate(object model) { // ... } } // Validator for Xyz class public class XyzValidator : IValidator { public bool Validate(object model) { // ... } }
You decide to create a factory class for the validators to prevent users from creating instances directly using the new keyword. For example, this code would create a validator for Foo:
var model = new Foo(); var validatorFactory = new ValidatorFactory(); IValidator validator = validatorFactory.CreateValidatorFor<Foo>(); if (validator.Validate(model)) { // ... }
Implementation of the factory:
using System; public class ValidatorFactory { public IValidator CreateValidatorFor<T>() { Type modelType = typeof (T); IValidator validator = CreateValidatorFor(modelType); return validator; } public IValidator CreateValidatorFor(Type modelType) { if (modelType == null) { throw new ArgumentNullException("modelType"); } if(modelType == typeof(Foo)) { return new FooValidator(); } else if(modelType == typeof(Bar)) { return new BarValidator(); } else if(modelType == typeof(Xyz)) { return new XyzValidator(); } string errorMessage = string.Concat("Could not find validator for type ", modelType.FullName); throw new ArgumentException("modelType", errorMessage); } }
As you can see, for each model you have an if statement. This works fine if you only need to create 2 or 3 validators but if you need more your code will get bigger and bigger and will be harder to read/maintain. The same applies to switch statements.
The first step to solve this problem is to create a Dictionary to store the validators. The key of the Dictionary will be the type of the model and the value will be a delegate that creates an instance of the validator for that model:
var validators = new Dictionary<Type, Func<IValidator>> { { typeof(Foo), () => new FooValidator() }, { typeof(Bar), () => new BarValidator() }, { typeof(Xyz), () => new XyzValidator() } };
Changing the implementation of the factory to use the dictionary:
public class ValidatorFactory : IValidatorFactory { private static Dictionary<Type, Func<IValidator>> _validators = new Dictionary<Type, Func<IValidator>> { { typeof(Foo), () => new FooValidator() }, { typeof(Bar), () => new BarValidator() }, { typeof(Xyz), () => new XyzValidator() } }; public IValidator CreateValidatorFor<T>() { Type modelType = typeof (T); IValidator validator = CreateValidatorFor(modelType); return validator; } public IValidator CreateValidatorFor(Type modelType) { if (modelType == null) { throw new ArgumentNullException("modelType"); } Func<IValidator> validatorFunc; if (_validators.TryGetValue(modelType, out validatorFunc)) { IValidator validator = validatorFunc(); return validator; } string errorMessage = string.Concat("Could not find validator for type ", modelType.FullName); throw new ArgumentException("modelType", errorMessage); } }
That’s it, code looks much nicer now! To configure a new validator just add a new key/value pair to the _validators Dictionary.
Finally, testing the code using NUnit:
// arrange var factory = new ValidatorFactory(); // act IValidator validator = factory.CreateValidatorFor<Foo>(); // assert Assert.That(validator, Is.TypeOf<FooValidator>());