Данные из корня иерархии
От: dmitry_npi Россия  
Дата: 15.09.16 14:39
Оценка:
Добрый день.

Допустим, есть у меня дерево, его вершины — объекты классов NodeClass1, NodeClass2 ... и RootNodeClass. То есть, например, класс RootNodeClass может создать у себя детей типа 1 и 2, в свою очередь NodeClass1 может иметь детей типа 1, 3, 4, ну и так далее в самых разных комбинациях.

И допустим, один из классов, NodeClassX, нуждается в данных, которые есть в корневой вершине, но его "предкам" эти данные не нужны.
Как правильно их туда передать?
Следует ли тащить эти данные через цепочку конструкторов? Тогда получится, что большинство классов будут тащить как бы лишний параметр в конструкторе.

Update:
В каждой вершине есть свойство Parent, однако оно заполняется после конструирования, тогда как данные из корня требуются уже в конструкторе класса NodeClassX.
Может быть, сделать так, чтобы конструкторы всех типов вершин обязательно требовали ссылку на предка?
Атмосферная музыка — www.aventuel.net
Отредактировано 15.09.2016 14:42 dmitry_npi . Предыдущая версия .
Re: Данные из корня иерархии
От: Carc Россия https://vk.com/gosha_mazov
Дата: 15.09.16 14:47
Оценка: 4 (1)
Здравствуйте, dmitry_npi, Вы писали:

_>Добрый день.


_>Допустим, есть у меня дерево, его вершины — объекты классов NodeClass1, NodeClass2 ... и RootNodeClass. То есть, например, класс RootNodeClass может создать у себя детей типа 1 и 2, в свою очередь NodeClass1 может иметь детей типа 1, 3, 4, ну и так далее в самых разных комбинациях.


_>И допустим, один из классов, NodeClassX, нуждается в данных, которые есть в корневой вершине, но его "предкам" эти данные не нужны.

_>Как правильно их туда передать?
_>Следует ли тащить эти данные через цепочку конструкторов? Тогда получится, что большинство классов будут тащить как бы лишний параметр в конструкторе.
А если передавать ссылку на RootNodeClass? Тогда всяким NodeClass1, NodeClass2 нет нужды знать определение корневого класса, а NodeClassX уже может (зная определение рут-класса) получать нужные ему данные, вызывая какой-то его метод. Правда, все равно понадобится, конечно, передавать через конструкторы.

Ну или вовсе передавать в конструкторе какой-то прокси объект, который содержит ссылку на RootNodeClass и знает как у него узнать данные. Но полностью скрывает другие его интерфейсы, выдавая какой-нить только один метод GetDataFromRoot, который де факто и будет общаться со ссылкой на рут-класс. Тогда по крайней мере нет необходимости дочерние класса знать про рут. Его полностью будет скрывать прокси-объект, разрешая только нужное и не более.
Aml Pages Home
Re[2]: Данные из корня иерархии
От: dmitry_npi Россия  
Дата: 15.09.16 16:29
Оценка:
Здравствуйте, Carc, Вы писали:

C>А если передавать ссылку на RootNodeClass? Тогда всяким NodeClass1, NodeClass2 нет нужды знать определение корневого класса, а NodeClassX уже может (зная определение рут-класса) получать нужные ему данные, вызывая какой-то его метод. Правда, все равно понадобится, конечно, передавать через конструкторы.


C>Ну или вовсе передавать в конструкторе какой-то прокси объект, который содержит ссылку на RootNodeClass и знает как у него узнать данные. Но полностью скрывает другие его интерфейсы, выдавая какой-нить только один метод GetDataFromRoot, который де факто и будет общаться со ссылкой на рут-класс. Тогда по крайней мере нет необходимости дочерние класса знать про рут. Его полностью будет скрывать прокси-объект, разрешая только нужное и не более.


Спасибо. В конце концов заставил все конструкторы принимать ссылку на родителя. Таким образом можно добраться до корня из любого места.
Атмосферная музыка — www.aventuel.net
Re: Данные из корня иерархии
От: fddima  
Дата: 15.09.16 16:32
Оценка:
Здравствуйте, dmitry_npi, Вы писали:

1. Я думаю любому ребенку следует знать о его родители, это классическая реализация xml документа. Соответсетвенно документ всегда достижим. Конечно в зависимости от необходимости можно оптимизировать доступ.

2. Посмотрите на Annotations в XObject. Суть в том что любой узел может хранить дополнительные данные (определенного типа). Это если нужно именно любые. Если они заранее известны — то проперти конечно.

Это общее решение которое годится для люьых деревьев. Доказано практикой — в дотнете расширяемся так — в браузере расширяем объект по необходимости.

Просто из описания не совсем ясно что нужно. Такой общий механизм избавил бы от деталей. Как пример в xml документе — позиция в файле хранится именно так — и только если парсеру об этом сказать — поэтому в нормальных случаях не платим за это.

Что подойдет вам... кто знает.
Re[3]: Данные из корня иерархии
От: fddima  
Дата: 15.09.16 16:35
Оценка:
Здравствуйте, dmitry_npi, Вы писали:

_>Спасибо. В конце концов заставил все конструкторы принимать ссылку на родителя. Таким образом можно добраться до корня из любого места.


Это правильное решение.
Re: Данные из корня иерархии
От: IQuerist Мухосранск  
Дата: 16.09.16 08:34
Оценка:
Здравствуйте, dmitry_npi, Вы писали:

_>И допустим, один из классов, NodeClassX, нуждается в данных, которые есть в корневой вершине, но его "предкам" эти данные не нужны.

_>Как правильно их туда передать?
_>Следует ли тащить эти данные через цепочку конструкторов? Тогда получится, что большинство классов будут тащить как бы лишний параметр в конструкторе.

А вы точно не пытаетесь запихнуть элементы внешнего алгоритма внутрь дерева, роль которого — контейнер?
Re: Данные из корня иерархии
От: Sinix  
Дата: 16.09.16 09:30
Оценка:
Здравствуйте, dmitry_npi, Вы писали:

_>Update:

_>В каждой вершине есть свойство Parent, однако оно заполняется после конструирования, тогда как данные из корня требуются уже в конструкторе класса NodeClassX.
_>Может быть, сделать так, чтобы конструкторы всех типов вершин обязательно требовали ссылку на предка?

Если речь про шарп, то классика выглядит так:
1.
  OwnedCollection
    // код древнючий, как минимум nameof() надо использовать. И ошибки при работе с коллекцией ловить
    public abstract class OwnedCollection<TItem, TOwner> : Collection<TItem> // or KeyedCollection<TKey, TItem>
        where TItem : class
        where TOwner : class
    {
        private readonly TOwner m_Owner;
        private readonly Func<TItem, TOwner> m_GetOwner;
        private readonly Action<TItem, TOwner> m_SetOwner;

        protected OwnedCollection(
            TOwner owner,
            Func<TItem, TOwner> getOwner,
            Action<TItem, TOwner> setOwner)
        {
            Code.NotNull(owner, "owner");
            Code.NotNull(getOwner, "getOwner");
            Code.NotNull(setOwner, "setOwner");

            this.m_Owner = owner;
            this.m_GetOwner = getOwner;
            this.m_SetOwner = setOwner;
        }

        protected override void ClearItems()
        {
            foreach (var item in Items)
            {
                m_SetOwner(item, null);
            }
            base.ClearItems();
        }

        protected override void InsertItem(int index, TItem item)
        {
            Code.AssertState(m_GetOwner(item) == null, "Item is mapped to another owner.");
            base.InsertItem(index, item);

            m_SetOwner(item, m_Owner);
        }

        protected override void RemoveItem(int index)
        {
            var item = this[index];
            base.RemoveItem(index);
            m_SetOwner(item, null);
        }

        protected override void SetItem(int index, TItem item)
        {
            Code.AssertState(m_GetOwner(item) == null, "Item is mapped to another owner.");

            m_SetOwner(this[index], null);
            base.SetItem(index, item);
            m_SetOwner(item, m_Owner);
        }
    }


2. Список подузлов хранится в коллекции — наследнике OwnedCollection.
3. Узел реализует collection initializer pattern (c c#6 достаточно extension method с именем Add). Позволяет собирать дерево примерно так:
            var schema = new Tag("SOMETAG")
            {
                Attributes =
                {
                    { "version", "0.1" }
                },
                Tags = 
                {
                    new Tag("Subtag")
                    {
                        new Attribute("SomeFieldAttribute", n => GetSomeField(n)),
                        new Attribute("Field2Attribute", n => GetField2(n)),
                        new Tag("Subtag2")
                        {
                            ...
                        ),
                        new Tag("Subtag3")
                        {
                            ...
                        }
                    },
                    GetMoreTags()
                }
            };


4. Делаем Extension-метод IEnumerable<Node> Ancestors(), который ч/з yield return перебирает всех родителей + IEnumerable<TNode> Ancestors<TNode>(), который возвращает только родителей заданного типа. Позволяет вытащить свойства из узлов выше по дереву.
5. Всё, что зависит от родителей прячется за Lazy<TValue>, после смены родителя Lazy сбрасываются.
6. Если надо проверить дерево в сборе — добавляем метод Init(), наследники в нём заполняют нужные свойства, ну и запрещаем изменение дерева после вызова этого метода.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.