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 负责存储球并删除它们。两名球员使用同一个球是完全可能的。

当一个球员被删除时,如果球不再被使用,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);
}

如果上面的代码中没有任何其他更改,那么如果其他玩家不再使用之前的 Ball 将被删除。这在实现 undo() 方法时会出现问题:如果前一个球已被删除,我不知道它的特征是什么,并且 undo 命令将无法重新创建它。或者也许我应该存储前一个球,但是撤消/重做命令如何知道这个前一个球是否仍然存在或已被处理程序删除?或者也许应该在撤消命令中实现这种一旦不再使用就删除球的机制?问题是 undo 命令会对许多其他类有很多依赖。另一个问题是此代码将在 DeletePlayer 命令中部分重复,这将不得不执行类似的操作:

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

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

我希望我的解释可以理解!

你将如何解决这个问题?我找不到令人满意的解决方案。

谢谢 !

4

3 回答 3

1

如果其他玩家不再使用球将被删除

正如我所看到的 - 它有s the source of your doubts. Certainly undo() command shouldn't recreate an object nor have it自己的删除机制。您的 GeneralHandler.isNotUsedAnymore() 是如何工作的?如果它计算对球的引用,那么对 ChangePlayerBall 实例的引用也应该被计算在内。因此,需要将 Command 对象连接到一些 GeneralHandler 的插槽。

所以,我建议:

  1. 球在没有被任何玩家任何 UndoCommands 使用时被删除(可能包括颜色变化等)
  2. 正如你所做的那样,球和球员之间的联系会在新的球分配上刹车
  3. 命令对象析构函数上的球和命令制动器之间的链接(当它完全从堆栈中删除时)

希望能帮助到你 )

于 2008-12-16T09:08:23.403 回答
0

对球使用引用计数技巧怎么样?当球被存储在命令中时,命令可以增加球的引用计数,从而防止被处理程序(或自身,取决于您将如何更改实现)删除。

于 2009-05-28T20:26:54.883 回答
0
  1. 将球保存在命令的构造函数中。
  2. 需要时放入/取出。
  3. 在任何地方都使用 QSharedPointer 来防止内存泄漏。
于 2010-12-01T08:12:14.310 回答