8.备忘录模式

8.行为型模式-备忘录模式


8.1 基础知识

学习难度:2

使用频率:2

总分:6

定义

备忘录模式(Memento Pattern)在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这状态。这样以后就可以将该对象恢复到原先保存的状态。

说人话

备忘录存储状态,管理者管理备忘录,原发器可以返回备忘录存档或传入备忘录读档得到状态。

结构图

实现步骤

  • 备忘录类:定义状态变量并在构造函数初始化赋值。
  • 管理者类:定义可读可写的备忘录对象。
  • 原发器类:定义可读可写的状态变量。定义创建备忘录方法,返回传入当前状态新实例化的备忘录对象。定义恢复状态方法,接收备忘录对象,将备忘录对象的状态设置给当前原发器对象的状态。
  • 客户端:创建原发器,创建管理者,设置原发器状态。调用原发器创建备忘录方法,并赋值给管理者的备忘录。修改原发器状态。调用原发器恢复状态方法,传入管理者的备忘录。打印查看原发器的状态是否恢复。

说明

备忘录模式允许对象在不暴露其内部状态的情况下捕获并保存当前状态,以后可以将其恢复到先前的状态。


8.2 模版代码

备忘录类

// 备忘录类,保存发起人的状态
class Memento
{
    public string State { get; private set; }

    public Memento(string state)
    {
        State = state;
    }
}

管理者类

// 管理者类,负责管理备忘录
class Caretaker
{
    public Memento Memento { get; set; }
}

发起人类

// 发起人类,负责创建备忘录和恢复状态
class Originator
{
    private string state;

    public string State
    {
        get { return state; }
        set
        {
            state = value;
            Console.WriteLine("设置状态为:" + state);
        }

    }

    // 创建备忘录,将当前状态保存到备忘录对象中
    public Memento CreateMemento()
    {
        Console.WriteLine("创建备忘录");
        return new Memento(state);
    }

    // 从备忘录对象中恢复状态
    public void RestoreMemento(Memento memento)
    {
        state = memento.State;
        Console.WriteLine("恢复状态为:" + state);
    }
}

客户端

class Program
{
    static void Main(string[] args)
    {
        // 创建发起人和管理者
        Originator originator = new Originator();
        Caretaker caretaker = new Caretaker();

        // 设置发起人的状态,并创建备忘录
        originator.State = "状态1"; //设置状态为:状态1
        caretaker.Memento = originator.CreateMemento(); //创建备忘录
        
        // 修改发起人的状态
        originator.State = "状态2"; //设置状态为:状态2

        // 恢复状态
        originator.RestoreMemento(caretaker.Memento); //恢复状态为:状态1

        Console.ReadKey();
    }
}

8.3 CSharp实践

实践需求

使用备忘录模式,模拟玩家恢复分数。玩家可以在游戏中获得分数并保存,然后在需要时恢复到以前的分数状态。

备忘录类

// 备忘录类,保存玩家分数的状态
class ScoreMemento
{
    public int Score { get; private set; }

    public ScoreMemento(int score)
    {
        Score = score;
    }
}

玩家类

// 玩家类,负责记录分数和管理备忘录
class Player
{
    private int score = 0;

    // 玩家获得分数
    public void EarnPoints(int points)
    {
        score += points;
    }

    // 获取当前分数
    public int GetScore()
    {
        return score;
    }

    // 创建备忘录,保存当前分数状态
    public ScoreMemento CreateMemento()
    {
        return new ScoreMemento(score);
    }

    // 恢复分数状态
    public void Restore(ScoreMemento memento)
    {
        score = memento.Score;
    }
}

客户端

class Program
{
    static void Main(string[] args)
    {
        Player player = new Player();
        ScoreMemento savedScore;

        // 玩家获得一些分数
        player.EarnPoints(50);
        savedScore = player.CreateMemento(); // 保存备忘录

        player.EarnPoints(30);
        player.EarnPoints(20);
        Console.WriteLine("当前分数:" + player.GetScore()); //当前分数:100

        // 玩家犯了一个错误,需要撤销操作
        player.Restore(savedScore); // 恢复到之前的分数状态

        Console.WriteLine("当前分数:" + player.GetScore()); //当前分数:50
    }
}

8.4 Unity实践

实践需求

实现切换英雄,销毁英雄,显示英雄,读档英雄,存档英雄逻辑。

英雄备忘录

//英雄备忘录
public class HeroMemento
{
    public GameObject Hero { get; private set; }

    public HeroMemento(GameObject hero)
    {
        Hero = hero;
    }
}

英雄备忘录管理器

//英雄备忘录管理器
public class HeroCaretaker
{
    public HeroMemento HeroMemento { get; set; }
}

英雄原发器类

// 英雄原发器类
public class HeroOriginator
{
    public GameObject Hero { get; set; }          // 存储英雄对象
    public GameObject HeroInstance { get; set; }  // 存储英雄实例对象

    public HeroOriginator(GameObject hero)
    {
        Hero = hero;
    }

    // 创建备忘录,保存当前状态
    public HeroMemento CreateMemento()
    {
        return new HeroMemento(Hero); // 创建一个备忘录对象,保存当前英雄状态
    }

    // 恢复到备忘录中保存的状态
    public void RestoreMemento(HeroMemento heroMemento)
    {
        if (heroMemento == null) return; // 如果备忘录为空,不执行恢复操作
        Hero = heroMemento.Hero; // 恢复英雄状态为备忘录中保存的状态
        ShowHero(); // 显示恢复后的英雄状态
    }

    public void ChangeHero(GameObject hero)
    {
        Hero = hero; // 更改当前英雄对象为传入的英雄对象
        ShowHero(); // 显示新的英雄状态
    }

    public void ShowHero()
    {
        if (Hero != null)
        {
            DestroyHero(); // 销毁当前英雄实例对象
            HeroInstance = GameObject.Instantiate(Hero); // 创建新的英雄实例对象
        }
    }

    public void DestroyHero()
    {
        if (HeroInstance != null) GameObject.Destroy(HeroInstance); // 销毁当前英雄实例对象
    }
}

客户端

public class TestMementoPattern : MonoBehaviour
{
    public List<GameObject> heroList; // 存储不同英雄对象的列表
    public int heroIndex; // 当前英雄索引

    public int HeroIndex
    {
        get
        {
            int beforeHeroIndex = heroIndex;
            do
            {
                heroIndex = Random.Range(0, heroList.Count); // 生成一个随机的英雄索引
            } while (heroIndex == beforeHeroIndex); // 确保新的索引与之前的索引不同

            return heroIndex; // 返回新的英雄索引
        }
    }

    public Button changeHeroButton; // 切换英雄按钮
    public Button showHeroButton; // 显示英雄按钮
    public Button restoreHeroButton; // 恢复英雄按钮
    public Button saveHeroButton; // 保存英雄按钮
    public Button destroyHeroButton; // 销毁英雄按钮

    private void Start()
    {
        // 创建英雄原发器对象,初始状态为随机选择的一个英雄
        HeroOriginator heroOriginator = new HeroOriginator(heroList[HeroIndex]);

        // 创建英雄负责人对象,用于保存备忘录
        HeroCaretaker heroCaretaker = new HeroCaretaker();

        // 初始化备忘录,保存当前英雄状态
        heroCaretaker.HeroMemento = heroOriginator.CreateMemento();

        // 为按钮添加点击事件监听器,以便执行相应的操作
        changeHeroButton.onClick.AddListener((() => { heroOriginator.ChangeHero(heroList[HeroIndex]); }));
        showHeroButton.onClick.AddListener((() => { heroOriginator.ShowHero(); }));
        restoreHeroButton.onClick.AddListener((() =>
        {
            heroOriginator.RestoreMemento(heroCaretaker.HeroMemento);
        }));
        saveHeroButton.onClick.AddListener((() => { heroCaretaker.HeroMemento = heroOriginator.CreateMemento(); }));
        destroyHeroButton.onClick.AddListener((() => { heroOriginator.DestroyHero(); }));
    }
}

运行结果



转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏