I have a situation where I need to use person's height in different units. Some parts of the system use Inches/Feet some Meters/Centimeters.
I was thinking of a Height value object which would encapsulate different measurement untis, and upon creation calculate and store all supported measurement units and provide accessors to get each.
I end up with this
public class Height : IEquatable<Height>
{
private Height()
{ }
public double InMeters { get; private set; }
public double InFeet { get; private set; }
public double InInches { get; private set; }
public static Height FromCMeters(double heightInCms) => new Height
{
InMeters = (double) heightInCms / 100,
InFeet = heightInCms * 30.48,
InInches = heightInCms * 2.54
};
public static Height FromFoots(double feet) => new Height
{
InFeet = feet,
InMeters = (feet * 30.48) / 100,
InInches = feet * 12
};
public static Height FromInches(double inches) => new Height
{
InInches = inches,
InFeet = inches / 12,
InMeters = (inches * 2.54) / 100
};
public bool Equals(Height other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return InMeters.Equals(other.InMeters);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((Height) obj);
}
public override int GetHashCode() => InMeters.GetHashCode();
}
I intentionally omitted addition/subsctraction to keep code small. The usage of Height value object:
var height = Height.FromCMeters(191);
// height.InMeters
// height.InInches
// height.InFeet
I have few doubts:
- If I need to support new unit of measure I would have to change the value object which I don't think is a good idea
- I tend to keep my value objects very small, this one seems to be doing too much for a value object (all those conversion logics)
- I think it keeps track of many values instead of a one, and it feels that all this conversion logic belongs to somewhere else
This Height VO is mostly going to be used to represent height. All operations are going to be creating height from different units (m/cm/feet/inch) and pass it around. Whoever receives it is going to use it just to retrieve height value in the unit it needs.
This simple usage makes me think I don't really need more involved design, where I would have simply Height VO (with single metric) and let another component do the necessary conversion.
What do you think ?