1

現在、プロジェクト用にいくつかのクラスを設計していますC++が、問題が発生しました。camera必要なすべての値(変換行列など)を保持するクラスを作成したいのですが、をレンダリングする関数はcamera交換可能である必要があります。これは、戦略パターンの通常のケースのように聞こえます。したがって、を定義するインターフェイスを作成し、このインターフェイスにクラスaをrender-function与えました。問題は、クラス内のすべてのデータにアクセスする必要があるため、この関数にパラメーターとしてクラスへのポインターを指定したことです。次のようになります。camerapointerrender functioncameracamera

#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()これは、インフィティループ( inrender-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-function(ユーザー入力に従ってカメラの新しい値のみを計算する)は、renderCamera-functionにアクセスできなくなります。このソリューションについてどう思いますか?

よろしくスタン

4

2 に答える 2

3

そうです、それは悪い設計のように思えます。:)

カメラ レンダーがカメラにアクセスする必要がある理由がわかりません。パラメータとして何か他のものを渡すことができると確信しています。レンダーはすべてのカメラ メンバーにアクセスする必要はないので、必要なものだけを渡すことができます (多数ある場合は、それらを構造体などでラップしますCameraConfig)。

異なるレンダリングに異なるパラメータが必要な場合は、 を使用して別の階層を作成できますICameraConfig

于 2012-09-28T08:30:23.403 に答える
2

特に、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 が提供する利点のいくつかを調べてみるとよいでしょう。それはあなたのコードを本当にクリーンアップし、より安全にします。(特に、shared/unique/etc ptr クラス。)

于 2012-09-28T17:23:06.413 に答える