Russian Qt Forum

Программирование => Общий => Тема начата: Igors от Сентябрь 23, 2017, 06:57



Название: Управление упорядоченными данными
Отправлено: Igors от Сентябрь 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 приватным методом? Другие решения?

Спасибо


Название: Re: Управление упорядоченными данными
Отправлено: ViTech от Сентябрь 23, 2017, 16:55
На мой объектно-ориентированный взгляд, основная проблема в этом:
Это однако никак не контролируется...

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


Название: Re: Управление упорядоченными данными
Отправлено: Igors от Сентябрь 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 - развалим доступ по индексу. А смысла отказываться от него нет - с немедленной пересортировкой (как в мапе) этот фрагмент превращается в геморрой


Название: Re: Управление упорядоченными данными
Отправлено: ViTech от Сентябрь 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 (http://en.cppreference.com/w/cpp/algorithm/for_each).

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