0

私のアプリケーションは Qt を使用して C++ で開発されており、シグナルとスロットを使用しています。

次のクラス (疑似 C++ コード) があるとします。

class Ball
{
    Color m_Color;
    int m_Size;
};

class Player
{
public:
    setBall(Ball* pBall)
    {
        if (pBall != m_pBall)
        {
            Ball* pPreviousBall = m_pBall;
            m_pBall = pBall;
            emit notifyBallNotUsed(pPreviousBall);
        }
    }

    Ball* getBall();

signals:
    void notifyBallNotUsed(Ball*);

private:
    String m_Name;
    Ball* m_pBall;
};

class GeneralHandler
{
public:
    addBall(Ball* pBall);
    deleteBall(Ball* pBall);


    addPlayer(Player* pPlayer)
    {
        connect(pPlayer, SIGNAL(notifyBallNotUsed(Ball*)), this, SLOT(onBallUsageChanged(Ball*)));
        ...
    }
    deletePlayer(Player* pPlayer);
    {
        disconnect(pPlayer, SIGNAL(notifyBallNotUsed(Ball*)), this, SLOT(onBallUsageChanged(Ball*)));

        onBallUsageChanged(pPlayer->getBall());
        ....
    }

private slots:
    void onBallUsageChanged(Ball* pBall)
    {
        if (isNotUsedAnymore(pBall))
        {
            m_BallList.remove(pBall);
            delete pBall;
        }
    }

private:
    bool isNotUsedAnymore(Ball* pBall); // Check if the given ball is still used by at least one player

    List<Player*> m_PlayerList;
    List<Ball*> m_BallList;
};

私のアプリケーションでは、ユーザーはプレーヤーを追加/削除でき、プレーヤーごとにボールの色とサイズを決定できます。内部では、GeneralHandler がボールの保存と削除を担当しています。2 人のプレーヤーが同じボールを使用する可能性は十分にあります。

プレーヤーが削除され、ボールがもう使用されていない場合、GeneralHandler はそれを削除する必要があります (または、ボールがまだ別のプレーヤーによって使用されている場合は保持します)。プレーヤーが使用しているボールが変更された場合、使用されなくなった前のボールも GeneralHandler によって削除される必要があります。

ここまでは順調ですね。

ここで、コマンド パターンを使用して元に戻す/やり直し機能をアプリケーションに追加したいと考えていますが、ここで行き詰まっています。私はこのようなものを持っているとしましょう:

class ChangePlayerBall : public QUndoCommand
{
public:
    ChangePlayerBall(Player* pPlayer, Ball* pNewBall)
    {
        m_pPlayer = pPlayer;
    }

    void redo();
    void undo();

private:
    Player* m_pPlayer;
};

redo() メソッドは次のようになると思います。

void ChangePlayerBall::redo()
{
    m_pPlayer->setBall(pNewBall);
}

上記のコードで他に何も変更されていない場合、以前のボールは他のプレイヤーによって使用されなくなった場合に削除されます。これは、undo() メソッドを実装するときに問題になります。前のボールが削除された場合、その特性が何であったかがわからず、元に戻すコマンドで再作成できません。または、前のボールを保存する必要がありますが、元に戻す/やり直しコマンドは、この前のボールがまだ存在するか、ハンドラーによって削除されたかをどのように認識しますか? それとも、ボールが使用されなくなったらすぐにボールを削除するこのメカニズムは、元に戻すコマンドで実装する必要がありますか? 問題は、元に戻すコマンドが他の多くのクラスに多くの依存関係を持つことです。もう 1 つの問題は、このコードが DeletePlayer コマンドで部分的に複製され、同様のことを行う必要があることです。

class DeletePlayer : public QUndoCommand
{
public:
    DeletePlayer(Player* pPlayer);

    void redo();
    void undo();
...
};

私の説明が理解できることを願っています!

この問題をどのように解決しますか? 私は満足のいく解決策を見つけることができません。

ありがとう !

4

3 に答える 3

0
  1. コマンドのコンストラクターでボールを保存します。
  2. 必要に応じて出し入れしてください。
  3. メモリ リークを防ぐために、どこでもボールに QSharedPointer を使用します。
于 2010-12-01T08:12:14.310 に答える
0

ボールに参照カウントのトリックを使用するのはどうですか? ボールがコマンドに格納されると、コマンドはボールの参照カウントをインクリメントできるため、ハンドラー (または実装の変更方法によってはそれ自体) によって削除されるのを防ぐことができます。

于 2009-05-28T20:26:54.883 に答える