Название: Выделить класс Отправлено: Igors от Май 28, 2016, 10:18 Добрый день
Есть такая структура (псевокод) Код И вот набегает набор методов посвященных манипуляциям с mRow, mColumn по чилдренам. Напр пересчитать все значения чтобы вставить новый чайлд в заданную строку/столбец. И наоборот, обеспечить нулевые минимальные строку/столбец после удаления чайлда. И другие. Это слабо связано с сущностью CNode и вполне может использоваться повторно (хотя пока такой необходимости нет). Стоит ли сразу же выделить управление mRow/mColumn в отдельный класс? Если да то как это лучше сделать? Спасибо Название: Re: Выделить класс Отправлено: Racheengel от Май 28, 2016, 10:30 а как mRow, mColumn связаны с index ?
что собой структура "физически" представляет? если у Вас есть что то типа CNode::insertChild(int index, int row, int col), то по хорошему этот метод должен заботиться об обновлении всех зависимых значений после вставки (если я правильно идею понимаю). То же самое при удалении. А значит, по идее должен быть какой-либо внешний контроллер, который бы хранил список всех нодов и их "связи" и обновлял их при необходимости. Но для этого надо знать структуру объектов. Название: Re: Выделить класс Отправлено: Igors от Май 28, 2016, 11:07 а как mRow, mColumn связаны с index ? То что и нарисовано вверху. По индексу получаем указатель на чайлда который имеет поля mRow, mColumn что собой структура "физически" представляет? если у Вас есть что то типа CNode::insertChild(int index, int row, int col), то по хорошему этот метод должен заботиться об обновлении всех зависимых значений после вставки (если я правильно идею понимаю). То же самое при удалении. Понимаете правильно, но сейчас пересчеты строки/столбца - ф-ционал конкретного класса CNode (его методы). А значит, по идее должен быть какой-либо внешний контроллер, который бы хранил список всех нодов и их "связи" и обновлял их при необходимости. "Хранилище" - сам CNode, он предоставляет интерфейс (см выше) для получения числа чайлдов (айтемов) и доступа к их полям строка/столбец. Напрашивается класс использующий этот интерфейс - но не завязанный жестко на CNodeНо для этого надо знать структуру объектов. Ну вот, опять проблемы с абстрактным мЫшлением :) Название: Re: Выделить класс Отправлено: Racheengel от Май 29, 2016, 00:38 Ну вот, опять проблемы с абстрактным мЫшлением :) Но Вы же ожидаете конкретного ответа, а не абстрактного? :) Что такое row и column для айтема? по какому принципу они должны меняться, если куда-то вдруг вставляется еще один чайлд? row и column это расположение айтема в какой-либо таблице, либо какие-либо внешние индексы, либо ... ? Ничего этого из приведенного описания класса не видно. О какой системе координат идет речь? Можно данные структуры предствить в "графическом" виде? Название: Re: Выделить класс Отправлено: Igors от Май 29, 2016, 07:03 row и column это расположение айтема в какой-либо таблице, Да, в QGridLayout (юзер может таскать из одной ячейки в другую)по какому принципу они должны меняться, если куда-то вдруг вставляется еще один чайлд? Напр юзер захотел вставить айтем слева и/или сверху, для текущего QGridLayout это будет ячейка напр (-2, -5). Но такого QGridLayout не понимает, вот и надо пересчитать все row, column. Также есть требование: слева, справа (сверху, снизу) вокруг ячейки с айтемом должны быть хотя бы 1 пустой столбец (строка). И.т.д. На первый взгляд это кажется совсем простым, но мне почему-то пришлось повозюкаться с этим не один день :) Не то чтобы "огромный" код - но ощутимый. И вот я смотрю на него и думаю: ну а CNode здесь причем? А значит... ???Название: Re: Выделить класс Отправлено: Racheengel от Май 29, 2016, 09:44 Я бы наверное row и column вынес из CNode в какой-нибудь CNodeManager, в котором бы имплементировалась вся логика переносов и пересчётов.
Почему так? Потому что row и column - это "внешние" атрибуты по отношению к ноде и могут меняться независимо от ее контента. А в менеджере будет что то типа typedef QPair<int,int> NodeIndex; QMap<NodeIndex, CNode*> mNode; ну и дальше делаем как то так: myManager->insertNode(-2, -5, new CNode(..)); // ну а тут все координаты всех нодов переколбашиваем читаем ноду: CNode* node = myManager->getNode(-2, -5); и т.д. "Усе через менежер". Что касается чайлдов, я так понимаю - это просто ссылки на связанные ноды? Название: Re: Выделить класс Отправлено: Igors от Май 29, 2016, 11:34 Что касается чайлдов, я так понимаю - это просто ссылки на связанные ноды? ДаЯ бы наверное row и column вынес из CNode в какой-нибудь CNodeManager, в котором бы имплементировалась вся логика переносов и пересчётов. Такой класс уже есть, но он занимается содержательной частью CNode (там еще масса всего). Поля mRow, mColumn в эту часть не входят - они как бы сами по себе, нет зависимостей от др членов CNodetypedef QPair<int,int> NodeIndex; Это не вносит никакой общности, по-прежнему завязано на CNode. Зато получаем новые мелкие заботы - напр при удалении CNode, сериализации и.т.п. Не вижу ничего плохого что CNode имеет поля строка/столбец QMap<NodeIndex, CNode*> mNode; Название: Re: Выделить класс Отправлено: Racheengel от Май 29, 2016, 13:30 А какое преимущество дает то, что mRow, mColumn находятся в ноде, а не в менеджере?
По вашему получается, что наоборот - сама по себе нода абсолютно не зависит от ее координат. И когда на поле появляется новая нода - то в текущем варианте Вам надо проапдейтить все объекты-ноды. А если бы их координаты жили только в менеджере - в сами ноды лезть бы не пришлось, достаточно обновить индексы в менеджере, и все. Да и сериализировать и удалять проще через менеджер, имхо. Проблем я не вижу, только преимущества. Название: Re: Выделить класс Отправлено: Igors от Май 30, 2016, 08:11 Да и сериализировать и удалять проще через менеджер, имхо. Проблем я не вижу, только преимущества. Тогда расскажите как сериализовать это typedef QPair<int,int> NodeIndex; QMap<NodeIndex, CNode*> mNode; Что будем писать/читать в поток вместо указателя на CNode ? Название: Re: Выделить класс Отправлено: Igors от Май 30, 2016, 08:22 И когда на поле появляется новая нода - то в текущем варианте Вам надо проапдейтить все объекты-ноды. А чем это лучше? Так я пробегаюсь по нодам, а так по контейнеру манагера - так его надо иметь и хранить (где?). И нод теряет самодостаточность, нуждается в помощи менеджера.А если бы их координаты жили только в менеджере - в сами ноды лезть бы не пришлось, достаточно обновить индексы в менеджере, и все. Как-то уперлись в один вариант (связка по мапе). Ну а почему не простейшее наследование, напр Код Теперь GridMan - законно общий класс. Что Вы об этом думаете? Название: Re: Выделить класс Отправлено: Racheengel от Май 30, 2016, 10:07 По сериализации: вместо поинтера пишем id ноды.
Собсвтвенно, при десериализации восстанавливаем. Без этого все равно никуда, как-то ж в любом случае надо связи восстанавливать. По общему классу: а кто будет обновлять в этом случае "соседние" ноды, если текущая изменилась (перетащили там или удалили-вставили)? Откуда GridMan будет знать, кого обновлять, кого нет? Название: Re: Выделить класс Отправлено: Igors от Май 30, 2016, 12:07 По сериализации: вместо поинтера пишем id ноды. Значит чтобы пользоваться такой конструкцией - надо обеспечить уникальное ID. Как-то это не очень "общо" :)Собсвтвенно, при десериализации восстанавливаем. Без этого все равно никуда, как-то ж в любом случае надо связи восстанавливать. По общему классу: а кто будет обновлять в этом случае "соседние" ноды, если текущая изменилась (перетащили там или удалили-вставили)? Откуда GridMan будет знать, кого обновлять, кого нет? Методы делающие содержательную работу (вставки/удаления) неизбежно есть, здесь они удачно ложатся в GridMan, напрКод В классе CNode я его не писал т.к. он не чисто виртуальный. Название: Re: Выделить класс Отправлено: Racheengel от Май 30, 2016, 13:01 Ну а как у Вас сейчас связь между нодами восстанавливается?
"Общий" ID можно тупо генерировать из поинтеров на ноды, тогда они гарантированно будут уникальными. Насчет SetNodePos не совсем понимаю. У Вас есть ноды 1,2,3,4. Вы меняете позицию ноды 2. Кто будет пересчитывать позиции для 1,3 и 4? Как это устроено? Название: Re: Выделить класс Отправлено: Igors от Май 31, 2016, 13:30 Насчет SetNodePos не совсем понимаю. Этот общий класс (GridMan) и будет, ведь у него есть доступ к позициям всех нодов (см перекрытые виртуалы) У Вас есть ноды 1,2,3,4. Вы меняете позицию ноды 2. Кто будет пересчитывать позиции для 1,3 и 4? Все-таки наследование мне здесь не очень нравится Название: Re: Выделить класс Отправлено: Racheengel от Май 31, 2016, 14:14 То есть КАЖДЫЙ GridMan, от которого наследуюется КАЖДАЯ нода, имеет доступ ко всем остальным нодам?
Как то совсем не хорошо... Вынесите GridMan в отдельный класс, пусть он будет "один для всех". А наследование тут не нужно. Название: Re: Выделить класс Отправлено: Igors от Май 31, 2016, 14:43 То есть КАЖДЫЙ GridMan, от которого наследуюется КАЖДАЯ нода, имеет доступ ко всем остальным нодам? Ко всем позициям чайлд-нодов данного нода. А про "собственно ноды" GridMan ничего не знает (что хорошо)Вынесите GridMan в отдельный класс, пусть он будет "один для всех". Синглтон что ли? Здесь явно не подходитДа, туговато идет, у меня впечатление что Вы постоянно забываете условие :) Ладно, переформулируем чуть иначе - Есть ф-ционал пересчета всех значений строк/столбцов при вставке/удалении в таблице. Ни с какой конкретной таблицей он не связан, поэтому и хочется сделать его отдельным классом (напр GridMan). Однако сами значения строк/столбцов удобнее хранить в самой таблице (или в др классе) где они непосредственно используются и сериализуются. Все что нужно GridMan - знать число ячеек и читать/писать значения строк/столбцов (не заботясь о том кому они принадлежат). Как должен выглядеть GridMan чтобы им удобно было пользоваться? Название: Re: Выделить класс Отправлено: Racheengel от Май 31, 2016, 15:25 Вот сейчас Вы описываете совершенно другую задачу, чем в начале...
Получается, что GridMan - это менеджер данных таблицы, который должен отслеживать вставку-удаление строк-столбцов таблицы и обновлять ее контент. То есть по сути это - некий контроллер, имеющий что-то типа OnRowInserted(MyTable* table, int row), OnColumnRemoved(MyTable* table, int column) и т.д. А куда ноды теперь подевались? Название: Re: Выделить класс Отправлено: Igors от Июнь 01, 2016, 17:57 Получается, что GridMan - это менеджер данных таблицы, который должен отслеживать вставку-удаление строк-столбцов таблицы и обновлять ее контент. То есть по сути это - некий контроллер, имеющий что-то типа OnRowInserted(MyTable* table, int row), OnColumnRemoved(MyTable* table, int column) и т.д. Хочется чтобы GridMan (и только он) отвечал за пересчет позиций всех ячеек. Ни о каком содержимом он не знает и понятия не имеет это таблица или еще кто. А обновлять контент будет тот кто его позовет (напр сама таблица). Ведь для собсно пересчетов строк/столбцов никакое UI не нужно. А вот читать пересчитанное могут многие - поэтому вариант с мапой не очень удобен.А куда ноды теперь подевались? Пока никуда :), это я хочу чтобы GridMan ничего о них не зналНазвание: Re: Выделить класс Отправлено: Racheengel от Июнь 01, 2016, 21:28 Ну ок, GridMan пересчитает значения в таблице и т.д. Да, ему гуй не нужен, это контроллер и ничего больше.
Получается, для каждой таблицы свой GridMan, так? А ноды то как обновляться будут? И где они тогда живут то? :) Название: Re: Выделить класс Отправлено: Igors от Июнь 02, 2016, 08:32 Ну ок, GridMan пересчитает значения в таблице и т.д. Да, ему гуй не нужен, это контроллер и ничего больше. Живут они в др структуре (графе). Есть довольно обильный UI (класс окна и др) которые и будут обновлять, визуализировать и.т.п. Получается, для каждой таблицы свой GridMan, так? А ноды то как обновляться будут? И где они тогда живут то? :) Вот "для каждой таблицы свой GridMan" мне не нравится. Обратите внимание что GridMan не имеет НИКАКИХ собственных данных/полей, он все берет из интерфейса "источника" (в данном случае CNode). В варианте с наследованием это недостаточно гибко - заточено на чайлды данного нода. В др ситуации напр никаких "нодов" нет, а есть просто виджеты (но опять-таки хранящие строку/столбец). Как тогда воспользоваться общим GridMan ? |