Throw Out Those Utility Classes
How many times have you written an xxxUtils
class, where xxx
is some framework supplied class that you can’t extend or subclass? I always seem to end up with several in any decent sized project, StringUtils
, DateUtils
, DictionaryUtils
, etc. In most cases, these classes are the result of language limitations. In Ruby and Smalltalk, for example, what would be the point of a StringUtils
class when you could simply add methods to the String
class directly? But C# and Java make String
sealed (final) so you can’t even subclass it.
Utility classes like these tend to suffer from logical cohesion. In spite of the friendly-sounding name, logical cohesion is actually a fairly weak form of cohesion; it’s just a loose jumble of functions that have something in common. It can in no way be considered object-oriented.
Our DictionaryUtils
makes an interesting case study because it was small. It only did two things: compared two dictionaries key-by-key for equality (useful in testing), and converting the entries to a Ruby-esque string. That last method made me a little jealous of how convenient Hashes are in Ruby:
middlestate:~ bhbyars$ irb
>> {'a' => 1, 'b' => 2, 'c' => 3}
=> {"a"=>1, "b"=>2, "c"=>3}
For the non-Ruby readers, I just created a 3-element Hash
in one line. The command-line interpreter spit out a string representation. Our DictionaryUtils.ConvertToText
could manage that last bit, but I wanted to be able to create hashtables as easily in C# as I could in Ruby. Naturally, that meant a third method on DictionaryUtils
. Or did it?
C# on Hash
DictionaryUtils.Create
seemed bloviated and ugly as soon as I first wrote it, so I quickly scratched it out and started a new class:
public class Hash
{
public static Hashtable New(params object[] keysAndValues)
{
if (keysAndValues.Length % 2 != 0)
throw new ArgumentException(“Hash.New requires an even number of parameters”);
Hashtable hash = new Hashtable();
for (int i = 0; i < keysAndValues.Length; i += 2)
{
hash[keysAndValues[i]] = keysAndValues[i + 1];
}
return hash;
}
}
This allowed me to create small loaded Hashtables
in one line, which was convenient, especially for test methods (although the syntax isn’t as explicit as Ruby’s). I then decided to merge the static DictionaryUtils
methods into Hash
, as instance methods. First, of course, I had to make Hash
an actual dictionary implementation. This was trivial:
private IDictionary proxiedHash;
public Hash(IDictionary dictionary)
{
proxiedHash = dictionary;
}
public bool Contains(object key)
{
return proxiedHash.Contains(key);
}
public void Add(object key, object value)
{
proxiedHash.Add(key, value);
}
public void Clear()
{
proxiedHash.Clear();
}
// etc…
Then I changed the return value of Hash.New
to a Hash
instead of a Hashtable
. The last line became return new Hash(hash)
instead of return hash
.
Next I moved the ConvertToText
method, which, as an instance method, conveniently mapped to ToString
.
public override string ToString()
{
SeparatedStringBuilder builder = new SeparatedStringBuilder(", ");
ICollection keys = CollectionUtils.TryToSort(Keys);
foreach (object key in keys)
{
builder.AppendFormat("{0} => {1}", Encode(key), Encode(this[key]));
}
return "{" + builder.ToString() + "}";
}
private object Encode(object value)
{
if (value == null)
return "<NULL>";
IDictionary dictionary = value as IDictionary;
if (dictionary != null)
return new Hash(dictionary).ToString();
if (value is string)
return "\"" + value + "\"";
return value;
}
The SeparatedStringBuilder
class is a StringBuilder
that adds a custom separator between each string. It’s very convenient whenever you’re a building a comma-separated list, as above. It’s proven to be handy in a variety of situations. For example, I’ve used it to build a SQL WHERE clause by making ” AND ” the separator. It’s included with the code download at the bottom of this article.
Notice, also, that we’re still using a CollectionUtils
class. Ah, well. I’ve got to have something to look forward to fixing tomorrow…
The DictionaryUtils.AreEqual
method conveniently maps to an instance level Equals
method:
public override bool Equals(object obj)
{
IDictionary other = obj as IDictionary;
if (other == null) return false;
Hash hash = new Hash(other);
return hash.ToString() == ToString();
}
public override int GetHashCode()
{
return proxiedHash.GetHashCode();
}
The syntax is much cleaner than the old DictionaryUtils
class. It’s nicely encapsulated, fits conveniently into the framework overrides, and is object-oriented, allowing us to add other utility methods to the Hash
class easily. It’s especially nice for testing, since the Equals
method will work against any dictionary implementation, not just Hashes:
Assert.AreEqual(Hash.New(“address”, customer.Address), propertyBag);
The approach was simple, relying on proxying for fulfilling the IDictionary
implementation (I’m probably abusing the word “proxying,” since we’re not doing anything with the interception. Really, this is nothing more than the Decorator design pattern). That was easy only because the framework actually provided an interface to subtype; the same isn’t true of String
and Date
. However, it isn’t true of StringBuilder
either; if you look at the code, SeparatedStringBuilder
looks like a StringBuilder
, it talks like a StringBuilder
, and it quacks like a StringBuilder
, but there is no syntactic relationship between them since StringBuilder
is sealed and doesn’t implement an interface. While the need for SeparatedStringBuilder
may represent a special case, I think I’d prefer creating similar-looking objects rather than relying on a framework-provided xxx
and a custom built xxxUtils
class. Proxying, as used by Hash
, generally makes such implementations trivial and clean, leaving you to spend your time developing what you really want without making the API unnecessarily ugly.
All the code needed to compile and test the Hash class can be found here.