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>());