使用自动删除机制撤消重做

时间:2008-12-09 13:50:05

标签: design-patterns qt

我的应用程序是使用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 / redo命令将如何知道? 或者也许这种在不再使用时删除球的机制应该在撤销命令中实现?问题是undo命令会对很多其他类有很多依赖。另一个问题是这个代码会在DeletePlayer命令中部分重复,它必须做类似的事情:

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

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

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

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

谢谢!

3 个答案:

答案 0 :(得分: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. 命令对象析构函数中的球和命令制动器之间的链接(当它从堆栈中完全移除时)
  4. 希望有所帮助)

答案 1 :(得分:0)

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

答案 2 :(得分:0)

  1. 在命令的构造函数中保存球。
  2. 需要时将其放入/取出。
  3. 在任何地方使用QSharedPointer来防止内存泄漏。