Возврат объектов, которые работают с данными родительского объекта и впоследствии делают их недействительными - PullRequest
2 голосов
/ 11 июня 2011

Я работаю над реализацией таблиц в приложении Qt, но у меня возникли некоторые проблемы с правильным дизайном.

У меня есть два класса, Table и Cell.

Cell имеет API для установки свойств ячейки, таких как границы и отступы, и получения строки и столбца ячейки с использованием int Cell::row() и int Cell::column(). Это явно совместно используемый класс, использующий QExplicitlySharedDataPointer для своих данных. Он также имеет isValid() API для запроса, действительна ли ячейка или нет.

Table имеет API для вставки / удаления строк и столбцов и объединения областей ячеек. Cell может быть получен из таблицы с использованием Table::cellAt(int row, int column). Ряды клеток хранятся как QList<QList<Cell>>. При удалении строк и столбцов удаленные ячейки помечаются таблицей как недействительные, что делает вызовы Cell::isValid в любых ранее возвращенных ячейках из удаленных строк / столбцов, возвращая значение false.

Теперь самое сложное: поскольку вычисление номера строки и столбца ячейки, если вы еще не получили их, является дорогостоящей операцией, методы Table::cellAt(int row, int column) явно задают строку / столбец в Cell перед возвратом. это и Cell сохраняет их как простые int члены. Это означает, что Cell может ответить быстро при запросе его строки / столбца.

Но тут возникает проблема; Это также означает, что значения Cell::row() и Cell::column будут неправильными, если строки или столбцы будут удалены / вставлены перед строкой / столбцом, в котором находится ячейка.

Я не могу пометить поврежденные ячейки как недействительные так же, как и я, когда фактическая строка / столбец, частью которого они являются, удалены. Позже кто-то может снова получить ячейку с cellAt(int, int) в этой строке / столбце. И эта ячейка не должна быть недействительной.

У кого-нибудь есть советы по улучшению дизайна здесь?

Ответы [ 2 ]

2 голосов
/ 11 июня 2011

Вы можете сделать ленивое обновление.То есть вместо обновления информации о позиции ячейки при каждом изменении таблицы обновляйте ее только при вызове Cell:row или Cell:column, если таблица изменилась с момента последнего обновления позиции ячейки.Это потребует от вас сохранить штамп версии или что-то в Table и Cell.Каждый раз, когда таблица обновляется, повышайте версию.Cell::row и Cell:column сначала проверит, старше ли версия Cell, чем Table, и если да, пересчитает позицию.

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

0 голосов
/ 13 июня 2011

Я обсуждал эту проблему с другом, потому что это было слишком похоже на упражнение «Программирование жемчуга».Вот что мы придумали:

  • Создать новую структуру для подсчета индексов.Это может быть что-то вроде struct Index { int n; };.
  • Хранить индексы строк и столбцов в двух QList<Index*>.Давайте назовем это Dimension.Использование указателя имеет решающее значение, как вы увидите позже.
  • Ячейки больше не сохраняют свои значения строк и столбцов.Они указывают на элемент в каждом из двух Dimension.При запросе их строки и столбца теперь имеется дополнительная разыменование указателя, которая не должна быть слишком дорогой.
  • Когда в таблицу добавляются или удаляются строки и столбцы, вы добавляете или удаляете элементы из соответствующих Dimension и обновите значение n следующих элементов.Хранение указателей необходимо, потому что QList копирует его значения.

Вместо перенумерации каждой ячейки, на которую воздействует обработка таблицы, операция, стоимость которой составляет O ( строк x столбцы ), теперь вы будете обновлять только затронутые строки или столбцы, стоимость которых равна O ( строк + столбцов ).Недостатком является сложность кода и два разыменованных доступа, когда ячейка запрашивается для ее строки или столбца.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...