Самое простое решение этой проблемы - разрешить дочерние мутации только через корневую сущность, что означает, что в идеале вы не должны открывать средства доступа для извлечения дочерних элементов, а если вы это сделаете, вы вернете копии для сохранения инкапсуляции. Этот подход обычно очень хорошо согласуется с моделью предметно-ориентированной предметной области.
Однако, если вы моделируете большие графоподобные структуры, вышеупомянутый подход может быть не очень практичным. В этом случае вы можете положиться на реализацию Observer Pattern или любого из его вариантов.
Обратите внимание, что моделирование очень больших корневых объектов часто является запахом кода, который может привести к проблемам с производительностью и конфликтам параллелизма. Корневая сущность должна быть настолько большой, насколько это необходимо для защиты бизнес-инвариантов.