While trying to model my domain, I came across the following problem. Let's image we have a Thing:
class Thing
{
public int X { get; set; }
}
Things have a property X. Then, there are Packs, which aggregate Things. But the domain requires that there is some restriction on the Things the Packs can hold. Let it be for example that the cumulative value of Xes can't be higher then some specific limit:
class Pack
{
private readonly List<Thing> myThings = new List<Thing>();
private const int MaxValue = 5;
public void Add(Thing thing)
{
if (myThings.Sum(t => t.X) + thing.X > MaxValue)
throw new Exception("this thing doesn't fit here");
myThings.Add(thing);
}
public int Count
{
get { return myThings.Count; }
}
public Thing this[int index]
{
get { return myThings[index]; }
}
}
So I check before adding a Thing to a Pack for the condition, but it's still so easy to get into troubles:
var pack = new Pack();
pack.Add(new Thing { X = 2 });
pack.Add(new Thing { X = 1 });
var thingOne = new Thing { X = 1 };
var thingTwo = new Thing { X = 3 };
//pack.Add(thingTwo); // exception
pack.Add(thingOne); // OK
thingOne.X = 5; // trouble
pack[0].X = 10; // more trouble
In C++ the solution would be to make a copy upon insertion and return const reference in the indexer. How to design around this problem in C# (and probably Java)? I just can't seem to think of a good solution:
- make Thing immutable - but what if it needs to be mutable?
- watch the Things in Pack with event/observer - but that means that Pack imposes the design of Thing; what if Things have more properties? Then I'll end up with just one event due to the need for Pack to watch for changes - that seems awkward to me.
Any ideas or preferred solutions?