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类就可以了。

相关推荐
闲人一枚(学习中)2 小时前
设计模式-创建型-抽象工厂模式
设计模式·抽象工厂模式
小白不太白9504 小时前
设计模式之 观察者模式
观察者模式·设计模式
小白不太白9505 小时前
设计模式之 责任链模式
python·设计模式·责任链模式
吾与谁归in6 小时前
【C#设计模式(13)——代理模式(Proxy Pattern)】
设计模式·c#·代理模式
吾与谁归in6 小时前
【C#设计模式(14)——责任链模式( Chain-of-responsibility Pattern)】
设计模式·c#·责任链模式
闲人一枚(学习中)6 小时前
设计模式-创建型-原型模式
设计模式
Iced_Sheep6 小时前
干掉 if else 之策略模式
后端·设计模式
哪 吒14 小时前
最简单的设计模式,抽象工厂模式,是否属于过度设计?
设计模式·抽象工厂模式
Theodore_102214 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
转世成为计算机大神17 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式