C++备忘录模式,状态模式(19,20)

备忘录模式

什么是备忘录模式

备忘录模式是一种行为设计模式, 允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态。(浏览器回退、编辑器撤销与重做、虚拟机生成快照与恢复、游戏悔棋等)

为什么使用备忘录模式

备忘录模式允许你复制对象中的全部状态 (包括私有成员变量), 并将其独立于对象进行保存。 尽管大部分人因为 “撤销” 这个用例才记得该模式, 但其实它在处理事务 (比如需要在出现错误时回滚一个操作) 的过程中也必不可少;备忘录让对象自行负责创建其状态的快照。 任何其他对象都不能读取快照, 这有效地保障了数据的安全性

备忘录模式实现步骤

1.提供一个原发器类:真正要被保存或恢复的对象,其负责创建一个备忘录,可以存储、恢复需要状态信息

2.提供一个备忘录类:用于存储原生器对象的的内部状态,防止外部直接访问原生器对象

3.提供一个管理者类:负责存储备忘录,但不能对备忘录内容进行操作和访问,只能将备忘录传递给其他对象  

//下棋退步问题
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Memento {
   public:
    Memento(string name, pair<int, int> pos) : name(name), pos(pos) {}
    string GetName() { return name; }
    pair<int, int> GetPos() { return pos; }
    void Show() {
        cout << name << ":(" << pos.first << "," << pos.second << ")" << endl;
    }

   private:
    string name;
    pair<int, int> pos;
};
class Chess {
   public:
    Chess(string name, pair<int, int> pos) : name(name), pos(pos) {}
    void SetChess(string name, pair<int, int> pos) {
        this->name = name;
        this->pos = pos;
    }
    Memento* SaveState() { return new Memento(name, pos); }
    void Restore(Memento* memento) {
        name = memento->GetName();
        pos = memento->GetPos();
    }

   protected:
    string name;
    pair<int, int> pos;
};

class Caretaker {
   public:
    //存档
    void AddMento(Memento* memento) {
        mementos.push_back(memento);
        step++;
    }
    //获取存档
    Memento* GetMemento(int index) {
        step = index;
        return mementos[step];
    }
    void Show() {
        for (int i = 0; i < step; i++) {
            cout << "step:" << i + 1 << "手" << endl;
            mementos[i]->Show();
        }
    }

   protected:
    vector<Memento*> mementos;
    static int step;
};
int Caretaker::step = 0;

int main() {
    Chess* pc = new Chess("车", {4, 3});
    Caretaker* pcaretaker = new Caretaker;
    pcaretaker->AddMento(pc->SaveState());
    pcaretaker->Show();

    cout << endl;
    pc->SetChess("马", {8, 8});
    pcaretaker->AddMento(pc->SaveState());
    pcaretaker->Show();

    cout << endl;
    pc->SetChess("炮", {6, 6});
    pcaretaker->AddMento(pc->SaveState());
    pcaretaker->Show();
    cout << endl;
    pc->Restore(pcaretaker->GetMemento(2));
    pcaretaker->Show();

    return 0;
}

备忘录模式优缺点

优点

  • 你可以在不破坏对象封装情况的前提下创建对象状态快照

  • 你可以通过让负责人维护原发器状态历史记录来简化原发器代码

缺点

  • 如果客户端过于频繁地创建备忘录, 程序将消耗大量内存

  • 负责人必须完整跟踪原发器的生命周期, 这样才能销毁弃用的备忘录

状态模式

什么是状态模式

状态模式是一种行为设计模式, 让你能在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样

为什么使用状态模式

模式建议你将所有特定于状态的代码抽取到一组独立的类中。 这样一来, 你可以在独立于其他状态的情况下添加新状态或修改已有状态, 从而减少维护成本;状态模式让你能够生成状态类层次结构, 通过将公用代码抽取到抽象基类中来减少重复

状态模式实现步骤

1.提供一个上下文环境类:抽象一个客户程序需要的接口,将与状态相关的操作委托给当前的具体状态类对象来处理

2.提供一个抽象给状态类:定义一个接口以封装使用上下文环境的的一个特定状态相关的行为

3.提供一个具体状态类:实现抽象状态定义的接口

//
#include <iostream>
using namespace std;
class Context;
class AbstractState {
   public:
    virtual void Handle(Context* p) = 0;
};
class ConcreteStateA : public AbstractState {
    void Handle(Context* p) { cout << "A....." << endl; }
};
class ConcreteStateB : public AbstractState {
    void Handle(Context* p) { cout << "B....." << endl; }
};

class Context {
   public:
    Context(AbstractState* pstate) : pstate(pstate) {}
    void Requst() {
        if (pstate) {
            pstate->Handle(this);
        }
    }
    void ChangeState(AbstractState* pstate) { this->pstate = pstate; }

   private:
    AbstractState* pstate;
};

int main() {
    AbstractState* pA = new ConcreteStateA;
    AbstractState* pB = new ConcreteStateB;
    Context* pC = new Context(pA);
    pC->Requst();
    pC->ChangeState(pB);
    pC->Requst();
    return 0;
}

状态模式优缺点

优点

  • 单一职责原则: 将与特定状态相关的代码放在单独的类中

  • 开闭原则: 无需修改已有状态类和上下文就能引入新状态

  • 通过消除臃肿的状态机条件语句简化上下文代码

缺点

  • 如果状态机只有很少的几个状态, 或者很少发生改变, 那么应用该模式可能会显得小题大作

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值