Вот общий сценарий, с которым мне всегда приходится сталкиваться.
У меня есть объектная модель с родительским объектом. Родитель содержит несколько дочерних объектов. Что-то вроде этого.
public class Zoo
{
public List<Animal> Animals { get; set; }
public bool IsDirty { get; set; }
}
Каждый дочерний объект имеет различные данные и методы
public class Animal
{
public string Name { get; set; }
public int Age { get; set; }
public void MakeMess()
{
...
}
}
Когда дочерний объект изменяется, в этом случае, когда вызывается метод MakeMess, необходимо обновить некоторое значение в родительском элементе. Скажем, когда определенный порог Animal сделал беспорядок, тогда необходимо установить флаг IsDirty в зоопарке.
Есть несколько способов справиться с этим сценарием (о которых я знаю).
1) Каждое животное может иметь ссылку на родительский зоопарк, чтобы сообщить об изменениях.
public class Animal
{
public Zoo Parent { get; set; }
...
public void MakeMess()
{
Parent.OnAnimalMadeMess();
}
}
Это похоже на худший вариант, поскольку он связывает Animal со своим родительским объектом. Что если я хочу животное, которое живет в доме?
2) Другой вариант, если вы используете язык, который поддерживает события (например, C #), это заставить родителя подписаться на изменение событий.
public class Animal
{
public event OnMakeMessDelegate OnMakeMess;
public void MakeMess()
{
OnMakeMess();
}
}
public class Zoo
{
...
public void SubscribeToChanges()
{
foreach (var animal in Animals)
{
animal.OnMakeMess += new OnMakeMessDelegate(OnMakeMessHandler);
}
}
public void OnMakeMessHandler(object sender, EventArgs e)
{
...
}
}
Это, кажется, работает, но из опыта становится трудно поддерживать. Если Животные когда-либо меняют зоопарк, вы должны отписаться от событий в старом зоопарке и повторно подписаться в новом зоопарке. Это только ухудшается, поскольку дерево композиции становится глубже.
3) Другой вариант - переместить логику к родителю.
public class Zoo
{
public void AnimalMakesMess(Animal animal)
{
...
}
}
Это кажется очень неестественным и вызывает дублирование логики. Например, если бы у меня был объект House, который не имеет общего родительского объекта наследования с Zoo ..
public class House
{
// Now I have to duplicate this logic
public void AnimalMakesMess(Animal animal)
{
...
}
}
Я еще не нашел хорошую стратегию для решения этих ситуаций. Что еще доступно? Как это можно сделать проще?