Apache Hash Code and Equals Builders
In the post I want to present two useful utility classes that for a long time are used in Java world and developed within Apache Software Foundation. These are HashCodeBuilder and EqualsBuilder classes which were ported by me in C#. To implement a good method of Hash Code and Equals for any class is not an easy task, but the classes assists implementing object.GetHashCode and object. Equals.
For equality comparation of objects should be used all relevant fields of the object, derived fields could be excluded. In order to build a Hash Code for an object is recommended to use same fields that were used for equality.
I like to learn by examples, so let’s to start one.
public class RgbColor
{
private readonly ushort r;
private readonly ushort g;
private readonly ushort b;
public RgbColor(ushort r, ushort g, ushort b)
{
this.r = r;
this.g = g;
this.b = b;
}
public ushort R
{
get { return r; }
}
public ushort B
{
get { return b; }
}
public ushort G
{
get { return g; }
}
That is an simple immutable POCO class that represents an RGB Color, and a typical implementation for the Equals and Hash Code are similar to:
public bool Equals(RgbColor other)
{
return other.r == r && other.g == g && other.b == b;
}
public override int GetHashCode()
{
int result = r.GetHashCode();
result = (result * 397) ^ g.GetHashCode();
result = (result * 397) ^ b.GetHashCode();
return result;
}
[NOTE: irrelevant code blocks are omitted]
TIP: these methods were generated using ReSharper.
As we can see same logic is repeated especially same mathematical and logical operations every time, DRY principle will argue us and finally the embracement will not let us sleep. What to do? Get some drugs?
Of course NO! Now we a lucky, we will apply HashCodeBuilder and and EqualsBuilder classes.public bool Equals(RgbColor other)
{
return new EqualsBuilder()
.Append(R, other.R)
.Append(G, other.G)
.Append(B, other.B)
.IsEquals();
}
public override int GetHashCode()
{
return new HashCodeBuilder()
.Append(R)
.Append(G)
.Append(B)
.ToHashCode();
}
With three primitive properties all is simple and nice but how to deal when we have collections, arrays, jagged arrays ect..?
Flowing test demonstrate Append method generality:
[Test]
public void testRaggedArray()
{
var array1 = new long[2][];
var array2 = new long[2][];
for (int i = 0; i < array1.Length; ++i)
{
array1[i] = new long[2];
array2[i] = new long[2];
for (int j = 0; j < array1[i].Length; ++j)
{
array1[i][j] = (i + 1) * (j + 1);
array2[i][j] = (i + 1) * (j + 1);
}
}
Assert.IsTrue(new EqualsBuilder().Append(array1, array1).IsEquals());
Assert.IsTrue(new EqualsBuilder().Append(array1, array2).IsEquals());
array1[1][1] = 0;
Assert.IsTrue(!new EqualsBuilder().Append(array1, array2).IsEquals());
}
You can discover more usages by taking a look to the unit tests that are ported too. OR taking a look to java classes documentation because the usage is almost compatible.
http://commons.apache.org/lang/api/org/apache/commons/lang/builder/EqualsBuilder.html
http://commons.apache.org/lang/api/org/apache/commons/lang/builder/HashCodeBuilder.html
http://www.java2s.com/Tutorial/Java/0500__Apache-Common/EqualsBuilder.htm
http://www.java2s.com/Tutorial/Java/0500__Apache-Common/HashCodeBuilder.htm
I’m sure that could be other implementations, based on attributes for the class proprieties and common implementation for the hash code and equal in the base class using reflection. I’m talking about something similar to the Sharp Architecture approach. However even in the case could be used the Builder classes for various type handling flexibility.
The classes are ported as part of Domain Driven Design Sample implemented in C#, so you can find within the trunk real usages of the classes.
So source for the classes is here:
About Domain Driven Design (DDD) Sample application I will blog more lately, for introduction in DDD in general please refer here.
For folks who want to know more about Builder pattern and Fluent interfaces can refer to my previous post.
Thank you for your attention,
Artur Trosin