Russian Qt Forum
Ноябрь 22, 2024, 10:52 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Управление упорядоченными данными  (Прочитано 3992 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Сентябрь 23, 2017, 06:57 »

Добрый день

Не первый раз возникает ситуация когда данные должны быть упорядочены по ключу (в данном случае "время"), но прямолинейное их хранение в мапе не годится - нужно обращение по индексу, для UI и не только. К тому же данные еще и полиморфны. Поэтому я выбрал такую организацию (псевдокод)
Код
C++ (Qt)
struct Key {
 double GetTime( void ) const  { return m_time; }
 void SetTime( double time );
 
 virtual QVariant GetData( void ) const = 0;
 virtual void SetData( const QVariant & v ) = 0;
 
private:
 double m_time;
 ...
};
 
struct Container {
  void SortByTime( void );
  ...
private:
 QVector<Key *> m_keys;
};
Да, но теперь, без иапы, нужно сортировать контейнер самому - а в какой момент это делать? Простейший вариант - пусть об этом заботится вызывающий, напр после вызова SetTime (изменил время ключа) вызвал SortByTime. Это однако никак не контролируется и возможностей насвистеть у вызывающего предостаточно. А несортированный контейнер начнет молотить полную фигню, напр
Код
C++ (Qt)
double Container::GetMinTime( void ) const
{
return m_keys.size() ? m_keys[0]->GetTime() : m_defaultTime;  // предполагается что m_keys упорядочены
}
 

Стоит ли упереться рогом и сделать Container::SortByTime приватным методом? Другие решения?

Спасибо
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #1 : Сентябрь 23, 2017, 16:55 »

На мой объектно-ориентированный взгляд, основная проблема в этом:
Это однако никак не контролируется...

С одной стороны Вы на внутреннее состояние контейнера накладываете ограничение (данные должны быть отсортированы), с другой стороны в Key::SetTime() позволяете это ограничение невозбранно нарушать. Одно из решений очевидно: разрешить только Container управлять временем его элементов. А так сами решайте что важнее: консистентное состояние контейнера, или сеттеры в элементах.
Записан

Пока сам не сделаешь...
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Сентябрь 24, 2017, 04:59 »

С одной стороны Вы на внутреннее состояние контейнера накладываете ограничение (данные должны быть отсортированы), с другой стороны в Key::SetTime() позволяете это ограничение невозбранно нарушать. Одно из решений очевидно: разрешить только Container управлять временем его элементов.
Хорошо, пусть сеттеры идут только через Container (кстати так уже и сделано). Но до решения еще далеко. Есть масса примерно такого кода
Код
C++ (Qt)
void SomeClass::OffsetTime( Container & c )
{
for (int i = 0; i < c.count(); ++i) {
  double dt = CalculateOffset(...);   // SomeClass умеет вычислять смещение
  c.SetKeyTime(c[i].GetTime() + dt);
}
c.SortByTime();
}
Сделать это методом Container явно "не то" (весь ф-ционал в CalcOffset). Бежать сразу сортировать в SetKeyTime - развалим доступ по индексу. А смысла отказываться от него нет - с немедленной пересортировкой (как в мапе) этот фрагмент превращается в геморрой
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #3 : Сентябрь 24, 2017, 12:00 »

Сделать это методом Container явно "не то" (весь ф-ционал в CalcOffset). Бежать сразу сортировать в SetKeyTime - развалим доступ по индексу. А смысла отказываться от него нет - с немедленной пересортировкой (как в мапе) этот фрагмент превращается в геморрой

В такой постановке задачи можно применить какую-нибудь вариацию паттерна Visitor, при которой контейнер может на время дать внешнему коду изменять свои внутренние данные, а затем привести их в порядок.

1. Специализированные редакторы: ContainerEditor с методом modify(ContainerData &). В Container тогда будет метод editBy(ContainerEditor &) вида:
Код
C++ (Qt)
Container::editBy(ContainerEditor & editor)
{
   editor.modify(m_data); // m_keys
   SortByTime();
}
2. Классический Visitor общего назначения.
3. Добавить в контейнер шаблонный метод типа forEach, аналогичный стандартному алгоритму std::for_each.

Можно ещё лучше поработать с предметной областью и связями между объектами, но это совсем другая история.
Записан

Пока сам не сделаешь...
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.124 секунд. Запросов: 23.