备忘录模式(memento)

文章目录

  • 1. 定义
  • 2. 实现
    • 2.1 cpp实现
    • 2.2 java实现
  • 3. 完整代码地址

1. 定义

GOF定义
Without violating encapsulation, capture and externalize an object’s internal
state so that the object can be restored to this state later.
在不破坏封装的前提下,捕获对象测内部状态,并在对象外部保存状态,以便在之后,能恢复这个状态。

备忘录模式的类图如下:

备忘录模式(memento)_第1张图片

备忘录模式可以分为如下三个角色:

  • originator : 需要保存状态的原始对象,根据这个对象创建出 memento 对象
  • memento : 保存原始对象的状态
  • caretaker : memento的持有者,可以持有多个memento

为什么需要一个memento对象,而不直接保存 originnator 了?

因为GOF的定义里提到 不要破坏封装, 通常 originnator 对象为了 处理业务逻辑, 会有很多处理业务逻辑的接口
而memento只是用来恢复originator, 不需要这些接口,如果暴露不需要的接口,就违反了封装原则. 所以需要 memento 对象。

2. 实现

我们打游戏的时候,会经用到 存档(save)/读档(load)。 这种场景就可以用 备忘录 模式。
比如我们正在撸dota,war3 就提供了 保存/读取 英雄状态 的能力
下面代码中:

  • Hero 对应类图中的 originator
  • Memento 对应类图中的 memento
  • War3 对应类图中的 caretaker

2.1 cpp实现

//author sbkun
#include 
#include 
#include 
using namespace std;

class Memento{
//为了少写几个get函数, 使用友元
friend class Hero;
public:
		Memento(int gold, int hp, const string& name) 
			: gold_(gold)
			, hp_(hp),
			, name_(name)
		{}
private:
		int gold_;
		int hp_;
		string name_;
};

class Hero{
	public:
		Hero() : gold_(9999)
			   , hp_(100)
			   , name_("mk")
		{}

		void beingAttacked(int damage) {
			hp_ -= damage;
		}

		shared_ptr<Memento> saveToMemento() {
			return shared_ptr<Memento>(new Memento(gold_, hp_, name_));
		}
		
		void restoreFromMemento(shared_ptr<Memento> p) {
			gold_ = p->gold_;
			hp_ = p->hp_;
			name_= p->name_;
		}
	
		ostream& print(ostream& os) const {
			return os<<"hero:"<<name_<<" gold:"<<gold_<<" hp:"<<hp_;
		}
	
	private:
		int gold_;
		int hp_;
		string name_;
};

ostream& operator<<(ostream& os, const Hero& w){
	return w.print(os);
}

class War3{
public:
	void save(shared_ptr<Memento> pMemento) {
		mementos_.push_back(pMemento);		
	}

	void load(shared_ptr<Hero> pHero) {
		if (!mementos_.empty())
		{
			shared_ptr<Memento> pMemento = mementos_.back();
			mementos_.pop_back();
			pHero->restoreFromMemento(pMemento);
		}
	}
private:
	list<shared_ptr<Memento>> mementos_;
};

int main(int argc, char* argv[])
{
	War3 war3;
	{
		shared_ptr<Hero> pHero = make_shared<Hero>();	
		war3.save(pHero->saveToMemento());
		cout<<*pHero<<endl<<endl;

		pHero->beingAttacked(40);
		cout<<"fuck ! my hero was attacked, hp reduced 40..."<<endl;
		cout<<*pHero<<endl<<endl;;

		war3.load(pHero);
		cout<<"don't worry! hero state reload..."<<endl;
		cout<<*pHero<<endl;
	}	

	return 0;
}

2.2 java实现

//author sbkun
package designpattern.behavioral;

import java.util.LinkedList;

class Hero {
    Hero(){
        this.hp = 100;
        this.name = "mk";
    }

    Memento saveToMemento() {
       return new Memento(this.name, this.hp);
    }

    void restoreFromMemento(Memento memento) {
       this.name = memento.name;
       this.hp = memento.hp;
    }

    void beingAttacked(int damage) {
       this.hp -= damage;
    }

    @Override
    public String toString() {
        return "Hero{" +
                "name='" + name + '\'' +
                ", hp=" + hp +
                '}';
    }

    private String name;
    private int hp;

//为了少写几个get,使用了静态内部类
    static class Memento {
        Memento(String name, int hp) {
            this.name = name;
            this.hp = hp;
        }
        private String name;
        private int hp;
    }
}

class War3 {
    void save(Hero.Memento memento) {
       mementos.add(memento);
    }

    void load(Hero hero) {
        if (!mementos.isEmpty()) {
            Hero.Memento memento = mementos.getLast();
            hero.restoreFromMemento(memento);
            mementos.removeLast();
        }
    }

    private LinkedList<Hero.Memento> mementos = new LinkedList<>();
}

public class MementoDemo {
    public static void main(String args[]) {
        War3 war3 = new War3();
        Hero hero = new Hero();
        war3.save(hero.saveToMemento());

        System.out.println(hero+"\n");

        hero.beingAttacked(40);
        System.out.println("fuck ! my hero was attacked, hp reduced 40...");
        System.out.println(hero+"\n");

        System.out.println("don't worry! hero state reload...");
        war3.load(hero);
        System.out.println(hero+"\n");
    }
}

3. 完整代码地址

该专栏的所有代码都已上传到github, 希望大家能多多批评指正
git链接

你可能感兴趣的:(设计模式,#,行为型模式)