QT设计模式:备忘录模式

**备忘录模式(Memento Pattern)**是一种行为型设计模式,主要用于保存一个对象当前的状态,并在需要时恢复该状态。它常应用于以下场景:

  1. 撤销操作:如文本编辑器撤销、软件开发中的版本控制等,用户可以返回到之前的状态。
  2. 备份和恢复:系统故障时,使用备份数据恢复到之前的状态,减少数据丢失风险。
  3. 系统快照:在执行高风险操作之前,创建系统状态的快照,方便后续进行回滚操作。

备忘录模式主要有三个参与者:发起人(Originator)、备忘录(Memento)和负责人(Caretaker)。发起人负责创建备忘录和恢复状态;备忘录负责存储发起人的状态信息;负责人管理多个备忘录。

QT示例:

Memento:增加一个Memento类去记录QTextEdit的字体和颜色;

MyCommand类:对应备忘录模式的Originator(发起人);

QUndoStack类:对应 Caretaker(负责人),负责管理撤销和重做操作,维护命令的历史记录。

#include <QApplication>
#include <QTextEdit>
#include <QUndoStack>
#include <QPushButton>
#include <QVBoxLayout>
#include <QUndoCommand>

class Memento {
public:
    Memento(const QString &text, const QFont &font, const QColor &color)
        : m_text(text), m_font(font), m_color(color) {}

    const QString& getText() const { return m_text; }
    const QFont& getFont() const { return m_font; }
    const QColor& getColor() const { return m_color; }

private:
    QString m_text;
    QFont m_font;
    QColor m_color;
};

class QUndoCommand
{
public:
    virtual ~QUndoCommand() {}
    virtual void undo() = 0;
    virtual void redo() = 0;
};

class MyCommand : public QUndoCommand {
public:
    MyCommand(QTextEdit *editor, const QString &text, const QFont &font, 
              const QColor &color, QUndoCommand *parent = nullptr)
        : QUndoCommand(parent), m_editor(editor),
          m_newMemento(std::make_shared<Memento>(text, font, color)) {

        m_oldMemento = std::make_shared<Memento>(editor->toPlainText(), 
                                                 editor->font(), editor->textColor());
    }

    void undo() override {
        m_editor->setPlainText(m_oldMemento->getText());
        m_editor->setFont(m_oldMemento->getFont());
        m_editor->setTextColor(m_oldMemento->getColor());
    }

    void redo() override {
        m_editor->setPlainText(m_newMemento->getText());
        m_editor->setFont(m_newMemento->getFont());
        m_editor->setTextColor(m_newMemento->getColor());
    }

private:
    QTextEdit *m_editor;
    std::shared_ptr<Memento> m_newMemento;
    std::shared_ptr<Memento> m_oldMemento;
};

class QUndoStack
{
public:
    void push(QUndoCommand *cmd)
    {
        m_stack.push(cmd);
        cmd->redo();
    }

    void undo()
    {
        if (!m_stack.isEmpty()) {
            QUndoCommand *cmd = m_stack.pop();
            cmd->undo();
            m_undoStack.push(cmd);
        }
    }

    void redo()
    {
        if (!m_undoStack.isEmpty()) {
            QUndoCommand *cmd = m_undoStack.pop();
            cmd->redo();
            m_stack.push(cmd);
        }
    }

private:
    QStack<QUndoCommand*> m_stack;
    QStack<QUndoCommand*> m_undoStack;
};

int main(int argc, char **argv) {
    QApplication app(argc, argv);

    QUndoStack stack;

    QTextEdit editor;
    QPushButton undoButton("Undo");
    QPushButton redoButton("Redo");

    QObject::connect(&undoButton, &QPushButton::clicked, &stack, &QUndoStack::undo);
    QObject::connect(&redoButton, &QPushButton::clicked, &stack, &QUndoStack::redo);

    // 假设用户通过一些方式,可以更改QTextEdit的字体和颜色
    QObject::connect(&editor, &QTextEdit::cursorPositionChanged, [&]() {
        QFont font = editor->font();
        QColor color = editor->textColor();
        stack.push(new MyCommand(&editor, editor.toPlainText(), font, color));
    });

    QVBoxLayout layout;
    layout.addWidget(&editor);
    layout.addWidget(&undoButton);
    layout.addWidget(&redoButton);

    QWidget window;
    window.setLayout(&layout);
    window.show();

    return app.exec();
}

在这个示例中,我们假设用户可以通过一些方式,可以更改QTextEdit的字体和颜色,并且这也需要做到撤销和重做。我们如果结合使用备忘录模式,增加一个Memento类去记录QTextEdit的字体和颜色,那么这个过程就简单的多了。否则,MyCommand类需要存储所有的状态,如果状态相关的数据对象越来越多,可能会导致MyCommand类的职责过重。

在这里,MyCommand类兼任了备忘录模式的Originator类和命令模式的Receiver类,QUndoStack类兼任了备忘录模式的Caretaker类和命令模式的Invoker类。所以实际上,命令模式和备忘录模式,可以简单理解为在命令模式的基础上增加一个Memento类就可以了。

相关推荐
lxyzcm6 小时前
深入理解C++23的Deducing this特性(上):基础概念与语法详解
开发语言·c++·spring boot·设计模式·c++23
越甲八千6 小时前
重温设计模式--单例模式
单例模式·设计模式
Vincent(朱志强)7 小时前
设计模式详解(十二):单例模式——Singleton
android·单例模式·设计模式
诸葛悠闲8 小时前
设计模式——桥接模式
设计模式·桥接模式
捕鲸叉12 小时前
C++软件设计模式之外观(Facade)模式
c++·设计模式·外观模式
小小小妮子~13 小时前
框架专题:设计模式
设计模式·框架
先睡13 小时前
MySQL的架构设计和设计模式
数据库·mysql·设计模式
Damon_X21 小时前
桥接模式(Bridge Pattern)
设计模式·桥接模式
越甲八千1 天前
重温设计模式--享元模式
设计模式·享元模式
码农爱java1 天前
设计模式--抽象工厂模式【创建型模式】
java·设计模式·面试·抽象工厂模式·原理·23种设计模式·java 设计模式