При попытке смоделировать свой домен я столкнулся со следующей проблемой.Давайте представим, что у нас есть Вещи:
class Thing
{
public int X { get; set; }
}
Вещи имеют свойство X. Затем, есть пакеты, которые объединяют Вещи.Но домен требует наличия некоторых ограничений на вещи, которые могут содержать пакеты.Пусть, к примеру, совокупное значение Xes не может быть выше определенного предела:
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]; }
}
}
Поэтому я проверяю перед добавлением Thing в пакет для условия, но все еще так легкопопасть в неприятности:
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
В C ++ решением было бы сделать копию при вставке и вернуть ссылку на констант в индексаторе.Как спроектировать эту проблему в C # (и, вероятно, Java)?Я просто не могу придумать хорошего решения:
- сделать Вещи неизменными - но что, если она должна быть изменчивой?
- смотреть Вещи в пакете с событием / наблюдателем- но это означает, что Pack навязывает дизайн Thing;что если вещи имеют больше свойств?Тогда я закончу только одним событием из-за необходимости, чтобы Пак следил за изменениями - это кажется мне неловким.
Какие-нибудь идеи или предпочтительные решения?
РЕДАКТИРОВАТЬ:
Возвращаясь к этому вопросу ... Я принял ответ Итай.Он прав.Первоначальная проблема заключалась в том, что из одного контекста вы хотели бы, чтобы объект Thing был неизменным, а из другого контекста вы хотели бы, чтобы он был изменяемым.И это требует отдельного интерфейса ... возможно.Я сказал «возможно», потому что в большинстве случаев Pack будет Агрегатом вещей (в смысле DDD) и, следовательно, будет владельцем объектов - это означает, что он не должен давать вам возможность изменять принадлежащий объект (либовернуть копию или вернуть неизменный интерфейс).
Приятно, что в C ++ эта конкретная вещь может быть легко обработана модификатором const.Похоже, гораздо меньше кодирования, если вы хотите, чтобы все было в согласованном состоянии.