Using the example of the class in Listing 1, the
state/strategy pattern will move each parameter check into its own object,
instead of creating a separate method for it. The key to implementing the
state/strategy pattern is to have a base class (ParameterCheck) that the
objects in the pattern will derive from. Below is a diagram of what this
relationship will look like.
Figure 1

Each object will override the IsValid method in
ParameterCheck to provide a more specific validation check. The State/Strategy
pattern works in this way, using inheritance to provide a means to add
unlimited number of derived classes. Both the State and Strategy pattern works
like this; however, state is often used for representing a state object and
strategy is often used for an algorithm of sorts. Compare the following
ParameterCheck definition over the previous code sample above.
Listing 2
public abstract class ParameterCheck
{
public abstract bool IsValid(object data, object argument);
}
That is quite a difference. ParameterCheck is now providing
an interface that all derived types must implement and so most of the actual
processing is now present in the concrete implementations TypeParameterCheck,
NullableParameterCheck, etc. To see what it looks like, the following is the definition
of TypeParameterCheck.
Listing 3
public class TypeParameterCheck: ParameterCheck
{
public override bool IsValid(object data, object argument)
{
if (!argument is Type)
throw new ArgumentException("The argument type is not valid");
return (data.GetType().IsAssignableFrom((Type)argument));
}
}
The following is the definition of NullableParameterCheck,
which takes a boolean value stating whether to ensure that a value is null or
to ensure it is not null, based on the value of the parameter.
Listing 4
public class NullableParameterCheck: ParameterCheck
{
public override bool IsValid(object data, object argument)
{
bool mustBeNulls;
if (argument == null)
mustBeNulls = false;
else
argument = (bool)argument;
if (mustBeNulls)
return (data == null);
else
return (data != null);
}
}
Any number of derivatives can be added. For instance,
assuming that we wanted to add the ability to validate based on a list of
values, we can do.
Listing 5
public class ValuesRangeParameterCheck: ParameterCheck
{
public override bool IsValid(object data, object argument)
{
if (!argument is object[])
throw new ArgumentException("The argument must be an array");
List < object > values = new List < object > ((object[])argument);
return values.Contains(data);
}
}
And the list could go on, based on whatever requirements we
may have. Inheritance allows the ability to create N number of parameter checks
without us having to have a definite list. However, there has to be a means to
expose each one, so at some point they need to be defined. A common way is to
create a custom configuration section, which can have an array of parameter
check class references. This is a similar concept to the membership element,
which has a list of providers that it contains. An alternative to this is to use
a Factory method, which can take a string, enum, or some other object that
uniquely references the correct parameter check.