Please see the code below:
public sealed class UKCurrency : ICurrency
{
private static readonly int _decimalPlaces=2;
private static readonly decimal[] _denominations = new decimal[] {
50.00M, 20.00M, 10.00M,
5.00M, 2.00M, 1.00M,
0.50M, 0.20M, 0.10M,
0.05M, 0.02M, 0.01M,
};
public IEnumerable<decimal> Denominations
{
get { foreach (var denomination in _denominations) yield return denomination; }
}
}
public sealed class DenominationCounter
{
private readonly decimal _cost;
public decimal Cost
{
get { return _cost; }
}
public ICurrency Currency
{
get { return _currency; }
}
public DenominationCounter(decimal cost, ICurrency currency)
{
if (currency == null)
throw new ArgumentNullException("Currency cannot be null", "ICurrency");
if (cost < 0)
throw new ArgumentException("Cost cannot be negative", "Cost");
if (decimal.Round(cost, currency.DecimalPlaces) != cost)
throw new ArgumentException(string.Concat("Cost has too many decimal places. It should only have: ", currency.DecimalPlaces), "Cost");
_cost = cost;
_currency = currency;
}
public IEnumerable<System.Collections.Generic.KeyValuePair<decimal, int>> CalculateDenominations()
{
var target = _cost;
foreach (var denomination in _currency.AvailableDenominations)
{
var numberRequired = target / denomination;
if (numberRequired >= 1)
{
int quantity = (int)Math.Floor(numberRequired);
yield return new KeyValuePair<decimal, int>(denomination, quantity);
target = target - (quantity * denomination);
}
}
}
}
The DenominationCounter constructor throws an exception if the cost has the wrong number of decimal places.
Notice that the UKCurrency class is used to validate the DenominationCounter as shown below:
if (decimal.Round(cost, currency.DecimalPlaces) != cost)
Is this a normal to approach validation like this:
1) A Value Objects member is used to validate an entity
2) A Value Objects member is used to validate another value object
I am asking this because I have never seen validation approached like this before and I am trying to follow the principle of least astonishment these days.