Рекурсивная стратегия

Я разрабатываю несколько классов для моего проекта в C++ на данный момент но у меня проблема.
Я хочу создать camera класс, который содержит все необходимые значения (например, матрицы преобразования), но функцию, которая отображает camera должен быть обменяемым. Это звучит как обычный случай для паттерна стратегии. Таким образом, я создал интерфейс, который определяет render-function и дал camera класс pointer к этому интерфейсу.
Проблема в том, что render function нужен доступ ко всем данным в camera класс, и поэтому я дал этой функции указатель на camera класс в качестве параметра. Это выглядит так:

#include "ICameraRender.h"
class Camera{
private:
ICameraRender*      _cameraRender;

public:
Camera();
Camera(ICameraRender& cameraRender);
~Camera();

void renderCamera(){  _cameraRender->render(this); }void setCameraRender(ICameraRender& cameraRender);
/..../

};class ICameraRender{
public:
virtual ~ICameraRender(){

}

//Override me
virtual void render(Camera* camera) = 0;
};

Это не кажется элегантным решением из-за ответственности за цикл бесконечности (вызов camera->renderCamera() в render-function в ICameraRender). Есть ли лучшее решение этой проблемы?

С уважением

РЕДАКТИРОВАТЬ:

Я придумал другое решение. Поскольку функция, которая работает с данными камеры, требует только доступа к данным, я думал, что смогу разделить сам класс камеры. Класс называется Camera и CameraModel. Последний содержит все необходимые данные, а первый выполняет операции с ним.
Поэтому мне просто нужно передать указатель на CameraModel в мою функцию:

class CameraModel{
private:
/...data.../
public:
/...setter and getter.../
};

class Camera{
private:
CameraModel*   _cameraModel;
ICameraRender* _cameraRender;

public:
Camera();
Camera(ICameraRender& cameraRender);
~Camera();

void renderCamera(){  _cameraRender->render(_cameraModel); }

void setCameraRender(ICameraRender& cameraRender);
/..../
};

class ICameraRender{
public:
virtual ~ICameraRender(){

}

//Override me
virtual void render(CameraModel* cameraModel) = 0;
};

Теперь функция render (которая только вычисляет новые значения для камеры в соответствии с пользовательским вводом) больше не имеет доступа к функции renderCamera.
Что вы думаете об этом решении?

С уважением, Стэн

1

Решение

Вы правы, это похоже на плохой дизайн. 🙂

Я не понимаю, почему для рендеринга камеры нужен доступ к камере. Я уверен, что вы можете передать что-то еще в качестве параметра. Для рендеринга не требуется доступ ко всем элементам камеры, поэтому вы можете просто передать те, которые им нужны (и, если их много, обернуть их в структуру CameraConfig или что-то типа того).

Если разным рендерам нужны разные параметры, вы можете создать отдельную иерархию с ICameraConfig,

3

Другие решения

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

Первое: заставьте ваш класс принять класс стратегии / политики (в данном случае ваш ICameraRenderer) с параметром шаблона. Затем укажите, что вы используете определенный метод из этого параметра шаблона. Сделайте вызовы этого метода в классе камеры …

Затем реализуйте свои стратегии как обычный старый класс с методом render ()!

Это будет выглядеть примерно так:

class Camera<RenderStrategy>{
using RenderStrategy::render;

/// bla bla bla

public:
void renderCamera(){  render(cameraModel); }
};

class SpiffyRender{
public:
void render(CameraModel orWhateverTheParameterIs){ // some implementation goes somewhere }
};

Всякий раз, когда вы хотите сделать камеру, которая использует одну из этих политик / стратегий:

// the syntax will be a bit different, my C++ chops are rusty;
// in general: you'll construct a camera object, passing in the strategy to the template  parameter
auto SpiffyCamera = new Camera<SpiffyRender>();

(Так как ваша стратегия рендеринга не имеет никакого состояния, это делает этот подход еще более благоприятным)

Если вы все время меняете свой рендерер, то этот шаблон / подход становится менее благоприятным … но если у вас есть камера, которая всегда делает один и тот же способ, это немного более хороший подход. Если у вашего рендерера есть состояние, вы все равно можете использовать этот метод; но вам понадобится ссылка на экземпляр внутри класса, и вы не будете использовать оператор Using ::. (В целом, при этом вы пишете меньше стандартного шаблона, вам не нужно делать какие-либо назначения или выделения во время выполнения, и компилятор работает для вас)

Подробнее об этом см .: http://en.wikipedia.org/wiki/Policy-based_design
Или читайте Modern C ++ Design … в любом случае это отличное чтение! http://www.amazon.com/Modern-Design-Generic-Programming-Patterns/dp/0201704315

Как не связанное в стороне: Вы можете рассмотреть некоторые из достоинств, которые дает вам C ++ x11. Это действительно очистит ваш код и сделает его более безопасным. (Особенно совместно используемые / уникальные / etc классы ptr.)

2

По вопросам рекламы [email protected]