The Descriptor Pattern

Well this is not any Gang of Four Design Pattern or a Martin Fowler’s Enterprise Application Architecture Pattern – this is just a trick of the object-oriented trade.

Suppose we have an enum named Heights as shown below-
enum Heights
{
VeryLow,
Low,
High,
VeryHigh
}
Now for the enum, everything is fine except that if we want to display its elements in a dropdown wherein we will have to display the texts for VeryLow and VeryHigh as Very Low(having a whitespace in between Very and Low) and Very High(having a whitespace in between Very and High) instead of as they are within the enum(using Heights.VeryLow.ToString() and Heights.VeryHigh.ToString() respectively).

One way to resolve this issue is to use constants as shown below –
public class Heights
{
public const string VeryLow = “Very Low”;
public const string Low = “Low”;
public const string High = “High”;
public const string VeryHigh = “Very High”;
}
The issue with the above solution is that it’s not type-safe.Say we have a method as shown below –
public bool HasHeight(string height)
{
return Height == height;
}
In the above code sample,”Height” is a class variable(of course a string) of the respective class.Now we can call something like HasHeight(Heights.VeryHigh) or HasHeight(“Very High”) from some other method, but both will return true if Height variable is set as “Very High”. Also we can call something like HasHeight(“Absurd”) and this won’t produce any compile time error.

The HasHeight method corresponding to the enum would be something like –
public bool HasHeight(Heights height)
{
return Height == height;
}
In the above code sample,”Height” is a class variable(of course of type Heights) of the respective class.In this case the variable can only have the enum values corresponding to the Heights enum and so it is type-safe(in this case, we cannot call something like HasHeight(“Absurd”) or HasHeight(Heights.Absurd) – being type-safe, both will produce compile time error).

So how do we achieve the type-safety of an enum along with displaying an enum member say VeryHigh as “Very High”?
Say Hello to the Descriptor Pattern.

A descriptor is a collection of instances of the class itself.The descriptor for the Heights enum would be something like the below class-

public class Heights
{
private readonly string heightDescription = String.Empty;
private static readonly IDictionary dict = new Dictionary();

public static readonly Heights VeryLow = new Heights(“Very Low”);
public static readonly Heights Low = new Heights(“Low”);
public static readonly Heights High = new Heights(“High”);
public static readonly Heights VeryHigh = new Heights(“Very High”);

private Heights(string heightDescription)
{
this.heightDescription = heightDescription;
dict.Add(heightDescription, this);
}

public override string ToString()
{
return heightDescription;
}

public static Heights Parse(string heightDescription)
{
if (dict.Keys.Contains(heightDescription))
{
return dict[heightDescription];
}
else
{
throw new NotImplementedException(“This height description is not supported currently.”);
}
}

public static bool TryParse(string heightDescription, out Heights height)
{
try
{
height = Parse(heightDescription);
return true;
}
catch (NotImplementedException ex)
{
height = null;
return false;
}
}

public static IListGetMembers()
{
return new List(dict.Values);
}
}

Now one can use Heights.VeryLow.ToString() and Heights.VeryHigh.ToString() to display “Very Low” and “Very High” respectively. The Parse and TryParse methods provided is similar to Enum.Parse and Enum.TryParse methods.As can be seen, the descriptor is very much type-safe just like an enum.The GetMembers method is provided to have an easy access to all the members of the Heights class.

Thanks to the Descriptor Pattern which allows to display an enum member such as VeryHigh as “Very High” in a totally type-safe manner.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s