Дизайн взаимодействия классов: агрегирование или дубликаты?

Рейтинг: 1Ответов: 1Опубликовано: 05.01.2015

У меня есть 2 класса:

class RecTarget : public Target /* Абстрактный */
{ /* Точки расположены в форме Прямоугольника */

  std::set<Point> Set;
  /* Множество позволяет быстро ответить:
   * "Было ли попадание в цель?" - в точку из Target
   */

  /* ... */
};

Есть class Target, хранит Points, в которые Actor должен попасть. И class Target может ответить быстро, попал он или нет.

class Moves
{ std::map< Point*, std::list<WayToGetTheHit> > hmoves;
  /* Следит и сохраняет движения, приведшие к попаданию,
   * для каждой точки Point из Target.
   */

   Target* target; /* Использовать агрегирование? Каким образом? */
   /* ... */
};

Есть class Moves, для каждого удачного попадания сохраняет способ его достижения: движения Аctor'а, время и т.д. для дальнейшего анализа. Moves хранит для каждой точки Point Target'а попадания в сортированном списке std::list.

Озадачен я тем, что Target хранит Points и Moves должен хранить (те же) Points, соответственные Target'у. Я могу подать все точки в конструктор Moves в один момент и забыть про Target, но это неправильно логически. Мне нужна какая-то связь между этими классами, чтобы обеспечить разделение между ними данных.

Как лучше это реализовать?

Использовать агрегирование, чтобы точки Moves ссылались на точки Target (указатель Point* на Target->Set->Point) (в случае если Target'ы могут быть разными (наследование) - это должен быть указатель? - это мне не очень нравится)?

Или лучше просто хранить дубликаты Points (мне тоже не очень нравится)?

Может, есть дизайн правильней и лучше?

Ответы

▲ 2Принят

Здесь можно использовать разделяемые указатели на Point. Они избавят от необходимости думать про ответственность какого-либо объекта за удаление точек.

В Qt - QSharedPointer<const Point>, в стандартной библиотеке c++11 - std::shared_ptr<const Point>.

class RecTarget : public Target /* Абстрактный */
{ /* Точки расположены в форме Прямоугольника */

  std::set<std::shared_ptr<const Point> > Set;
...

class Moves
{ std::map< std::shared_ptr<const Point>, std::list<WayToGetTheHit> > hmoves;

Если вы используете c++11, для hmoves можно выбрать std::unordered_map, чтобы уйти от непонятной логики сравнения этих указателей (поскольку std::map сортирует значения по ключам). Правда, в этом случае очевидно придётся написать однометодный класс хэширования std::hash<std::shared_ptr<Point> >, но тут чего-то сложного нет.

Сами указатели на точки могут создаваться в другом месте и лишь передаваться для хранения как в Moves, так и в Target.

Прибавка const к классу шаблона гарантирует неизменность значения, на которое ссылается хранимый указатель. (Очевидно, и Target, и Movies не должны менять точки)