欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C#備忘錄人生存檔的設(shè)計(jì)模式實(shí)例

 更新時(shí)間:2022年06月01日 16:26:53   作者:老胡寫(xiě)代碼  
這篇文章主要為大家介紹了C#設(shè)計(jì)模式中備忘錄模式的實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

C#備忘錄設(shè)計(jì)模式

大家好,老胡又和大家見(jiàn)面了。首先承認(rèn)今天的博客有點(diǎn)標(biāo)題黨了,人生是沒(méi)有存檔,也沒(méi)有后悔藥的。有存檔和后悔藥的,那是游戲,不知道這是不是游戲讓人格外放松的原因之一。

今天恰逢端午放假,就讓我們來(lái)試著做一個(gè)小游戲吧,順帶看看備忘錄模式是如何在這種情況下面工作的。

游戲背景

這是一個(gè)簡(jiǎn)單的打怪游戲,有玩家,有怪獸,玩家作為主角光環(huán),有如下三個(gè)特殊能力

  • 攻擊怪獸有暴擊幾率
  • 有幾率回避怪獸攻擊
  • 可以自己治療一定生命值

游戲?qū)崿F(xiàn)

角色類

角色基類

首先是角色類,角色類提供玩家和怪獸最基本的抽象,比如血量、攻擊力、攻擊和治療。(對(duì)于怪獸來(lái)說(shuō),治療是沒(méi)有提供實(shí)現(xiàn)的,壞人肯定不能再治療了)

class Character
{
    public int HealthPoint { get; set; }
    public int AttackPoint { get; set; }        
    public virtual void AttackChracter(Character opponent)
    {
        opponent.HealthPoint -= this.AttackPoint;
        if (opponent.HealthPoint < 0)
        {
            opponent.HealthPoint = 0;
        }
    }
    public virtual void Cure()
    {
		//故意留空給子類實(shí)現(xiàn)
    }
}

玩家類

玩家實(shí)現(xiàn)了治療功能并且有暴擊幾率。

class Player : Character
{
    private float playerCriticalPossible;
    public Player(float critical)
    {
        playerCriticalPossible = critical;
    }
    public override void AttackChracter(Character opponent)
    {
        base.AttackChracter(opponent);
        Console.WriteLine("Player Attacked Monster");
        Random r = new Random();
        bool critical = r.Next(0, 100) < playerCriticalPossible * 100;
        if (critical)
        {
            base.AttackChracter(opponent);
            Console.WriteLine("Player Attacked Monster again");
        }
    }
    public override void Cure()
    {
        Random r = new Random();
        HealthPoint += r.Next(5, 10);
        Console.WriteLine("Player cured himself");
    }
}

怪獸類

怪獸沒(méi)有治療能力但是有一定的幾率丟失攻擊目標(biāo)。

class Monster : Character
{
    private float monsterMissingPossible;
    public Monster(float missing)
    {
        monsterMissingPossible = missing;
    }
    public override void AttackChracter(Character opponent)
    {
        Random r = new Random();
        bool missing = r.Next(0, 100) < monsterMissingPossible * 100;
        if (missing)
        {
            Console.WriteLine("Monster missed it");
        }
        else
        {
            base.AttackChracter(opponent);
            Console.WriteLine("Monster Attacked player");
        }
    }
}

游戲類

游戲類負(fù)責(zé)實(shí)例化玩家和怪獸、記錄回合數(shù)、判斷游戲是否結(jié)束,暴露可調(diào)用的公共方法給游戲操作類。

class Game
{
    private Character m_player;
    private Character m_monster;
    private int m_round;
    private float playerCriticalPossible = 0.6f;
    private float monsterMissingPossible = 0.2f;
    public Game()
    {
        m_player = new Player(playerCriticalPossible)
        {
            HealthPoint = 15,
            AttackPoint = 2
        };
        m_monster = new Monster(monsterMissingPossible)
        {
            HealthPoint = 20,
            AttackPoint = 6
        };
    }
    public bool IsGameOver => m_monster.HealthPoint == 0 || m_player.HealthPoint == 0;
    public void AttackMonster()
    {            
        m_player.AttackChracter(m_monster);
    }
    public void AttackPlayer()
    {
        m_monster.AttackChracter(m_player);
    }
    public void CurePlayer()
    {
        m_player.Cure();
    }
    public void BeginNewRound()
    {
        m_round++;
    }
    public void ShowGameState()
    {
        Console.WriteLine("".PadLeft(20, '-'));
        Console.WriteLine("Round:{0}", m_round);
        Console.WriteLine("player health:{0}", "".PadLeft(m_player.HealthPoint, '*'));
        Console.WriteLine("monster health:{0}", "".PadLeft(m_monster.HealthPoint, '*'));
    }
}

游戲操作類

在我們這個(gè)簡(jiǎn)易游戲中,沒(méi)有UI代碼,游戲操作類負(fù)責(zé)在用戶輸入和游戲中搭建一個(gè)橋梁,解釋用戶的輸入。

class GameRunner
{
    private Game m_game;
    public GameRunner(Game game)
    {
        m_game = game;
    }
    public void Run()
    {
        while (!m_game.IsGameOver)
        {
            m_game.BeginNewRound();
            bool validSelection = false;
            while (!validSelection)
            {
            	m_game.ShowGameState();
                Console.WriteLine("Make your choice: 1. attack 2. Cure");
                var str = Console.ReadLine();
                if (str.Length != 1)
                {
                    continue;
                }
                switch (str[0])
                {
                    case '1':
                        {
                            validSelection = true;
                            m_game.AttackMonster();
                            break;
                        }
                    case '2':
                        {
                            validSelection = true;
                            m_game.CurePlayer();
                            break;
                        }
                    default:
                        break;
                }
            }
            if(!m_game.IsGameOver)
            {
                m_game.AttackPlayer();
            }
        }            
    }
}

客戶端

客戶端的代碼就非常簡(jiǎn)單了,只需要實(shí)例化一個(gè)游戲操作類,然后讓其運(yùn)行就可以了。

class Program
{
    static void Main(string[] args)
    {
        Game game = new Game();
        GameRunner runner = new GameRunner(game);
        runner.Run();
    }
}

試著運(yùn)行一下,

看起來(lái)一切都好。

加上存檔

雖然游戲可以正常運(yùn)行,但是總感覺(jué)還是少了點(diǎn)什么。嗯,存檔功能,一個(gè)游戲沒(méi)有存檔是不健全的,畢竟,人生雖然沒(méi)有存檔,但是游戲可是有的!讓我們加上存檔功能吧,首先想想怎么設(shè)計(jì)。

需要存檔的數(shù)據(jù)

首先我們要明確,有哪些數(shù)據(jù)是需要存檔的,在這個(gè)游戲中,玩家的生命值、攻擊力、暴擊率;怪獸的生命值、攻擊力和丟失率,游戲的回合數(shù),都是需要存儲(chǔ)的對(duì)象。

存檔定義

這是一個(gè)需要仔細(xì)思考的地方,一般來(lái)說(shuō),需要考慮以下幾個(gè)地方:

  • 存檔需要訪問(wèn)一些游戲中的私有字段,比如暴擊率,需要在不破壞游戲封裝的情況下實(shí)現(xiàn)這個(gè)功能
  • 存檔自身需要實(shí)現(xiàn)信息隱藏,即除了游戲,其他類不應(yīng)該訪問(wèn)存檔的詳細(xì)信息
  • 存檔不應(yīng)該和游戲存放在一起,以防不經(jīng)意間游戲破壞了存檔數(shù)據(jù),應(yīng)該有專門(mén)的類存放存檔

備忘錄模式出場(chǎng)

這個(gè)時(shí)候應(yīng)該是主角出場(chǎng)的時(shí)候了??纯磦渫浤J降亩x

在不破壞封閉的前提下,捕獲一個(gè)對(duì)象的內(nèi)部狀態(tài),并在該對(duì)象之外保存這個(gè)狀態(tài)。這樣以后就可將該對(duì)象恢復(fù)到原先保存的狀態(tài)

再看看UML,

看起來(lái)完全符合我們的需求啊,Originator就是游戲類,知道如何創(chuàng)造存檔和從存檔中恢復(fù)狀態(tài),Memento類就是存檔類,Caretaker是一個(gè)新類,負(fù)責(zé)保存存檔。

經(jīng)過(guò)思考,我們決定采取備忘錄模式,同時(shí)加入以下措施:

  • 將存檔定義為游戲中的私有嵌套類,這樣存檔可以毫無(wú)壓力的訪問(wèn)游戲中的私有字段,同時(shí)外界永遠(yuǎn)沒(méi)有辦法去實(shí)例化或者嘗試通過(guò)轉(zhuǎn)型來(lái)獲得這個(gè)類,完美的保護(hù)了存檔類
  • 存檔類是一個(gè)簡(jiǎn)單的數(shù)據(jù)集合,不包含任何其他邏輯
  • 添加一個(gè)存檔管理器,可以放在游戲操作類中,可以通過(guò)它看到我們當(dāng)前有沒(méi)有存檔
  • 存檔放在存檔管理器中
  • 存檔實(shí)現(xiàn)一個(gè)空接口,在存檔管理器中以空接口形式出現(xiàn),這樣外部類在訪問(wèn)存檔的時(shí)候,僅能看到這個(gè)空接口。而在游戲類內(nèi)部,我們?cè)谑褂么鏅n之前先通過(guò)向下轉(zhuǎn)型實(shí)現(xiàn)類型轉(zhuǎn)換(是的,向下轉(zhuǎn)型不怎么好,但是偶爾可以用一下)

空接口

interface IGameSave
{
}

私有嵌套存檔類

該類存放在game里面,無(wú)壓力地在不破壞封裝的情況下訪問(wèn)game私有字段

private class GameSave : IGameSave
{
    public int PlayerHealth { get; set; }
    public int PlayerAttack { get; set; }
    public float PlayerCritialAttackPossible { get; set; }
    public int MonsterHealth { get; set; }
    public int MonsterAttack { get; set; }
    public float MonsterMissingPossible { get; set; }
    public int GameRound { get; set; }
}

創(chuàng)建存檔和從存檔恢復(fù)

在game中添加創(chuàng)建存檔和從存檔恢復(fù)的代碼,在從存檔恢復(fù)的時(shí)候,使用了向下轉(zhuǎn)型,因?yàn)閺拇鏅n管理器讀出來(lái)的只是空接口而已

public IGameSave CreateSave()
{
    var save = new GameSave()
    {
        PlayerHealth = m_player.HealthPoint,
        PlayerAttack = m_player.AttackPoint,
        PlayerCritialAttackPossible = playerCriticalPossible,
        MonsterAttack = m_monster.AttackPoint,
        MonsterHealth = m_monster.HealthPoint,
        MonsterMissingPossible = monsterMissingPossible,
        GameRound = m_round
    };
    Console.WriteLine("game saved");
    return save;
}
public void RestoreFromGameSave(IGameSave gamesave)
{
    GameSave save = gamesave as GameSave;
    if(save != null)
    {
        m_player = new Player(save.PlayerCritialAttackPossible) { HealthPoint = save.PlayerHealth, AttackPoint = save.PlayerAttack };
        m_monster = new Player(save.MonsterMissingPossible) { HealthPoint = save.MonsterHealth, AttackPoint = save.MonsterAttack };
        m_round = save.GameRound;
    }
    Console.WriteLine("game restored");
}	

存檔管理器類

添加一個(gè)類專門(mén)管理存檔,此類非常簡(jiǎn)單,只有一個(gè)存檔,要支持多存檔可以考慮使用List

    class GameSaveStore
    {
        public IGameSave GameSave { get; set; }
    }

在游戲操作類添加玩家選項(xiàng)

首先在游戲操作類中添加一個(gè)存檔管理器

private GameSaveStore m_gameSaveStore = new GameSaveStore();

接著修改Run方法添加用戶操作

public void Run()
{
    while (!m_game.IsGameOver)
    {
        m_game.BeginNewRound();
        bool validSelection = false;
        while (!validSelection)
        {
            m_game.ShowGameState();
            Console.WriteLine("Make your choice: 1. attack 2. Cure 3. Save 4. Load");
            var str = Console.ReadLine();
            if (str.Length != 1)
            {
                continue;
            }
            switch (str[0])
            {
                case '1':
                    {
                        validSelection = true;
                        m_game.AttackMonster();
                        break;
                    }
                case '2':
                    {
                        validSelection = true;
                        m_game.CurePlayer();
                        break;
                    }
                case '3':
                    {
                        validSelection = false;
                        m_gameSaveStore.GameSave = m_game.CreateSave();
                        break;
                    }
                case '4':
                    {
                        validSelection = false;
                        if(m_gameSaveStore.GameSave == null)
                        {
                            Console.WriteLine("no save to load");
                        }
                        else
                        {
                            m_game.RestoreFromGameSave(m_gameSaveStore.GameSave);
                        }
                        break;
                    }
                default:
                    break;
            }
        }
        if(!m_game.IsGameOver)
        {
            m_game.AttackPlayer();
        }
    }            
}

注意,上面的3和4是新添加的存檔相關(guān)的操作。試著運(yùn)行一下。

看起來(lái)一切正常,這樣我們就使用備忘錄模式,完成了存檔讀檔的功能。

結(jié)語(yǔ)

這就是備忘錄模式的使用,如果大家以后遇到這種場(chǎng)景

  • 想要保存狀態(tài),又不想破壞封裝
  • 需要把狀態(tài)保存到其他地方

那么就可以考慮使用這個(gè)模式。

游戲有存檔,人生沒(méi)存檔,愿我們把握當(dāng)下,天天努力。

祝大家端午安康,更多關(guān)于C#備忘錄設(shè)計(jì)模式的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C# Windows API應(yīng)用之基于FlashWindowEx實(shí)現(xiàn)窗口閃爍的方法

    C# Windows API應(yīng)用之基于FlashWindowEx實(shí)現(xiàn)窗口閃爍的方法

    這篇文章主要介紹了C# Windows API應(yīng)用之基于FlashWindowEx實(shí)現(xiàn)窗口閃爍的方法,結(jié)合實(shí)例形式分析了Windows API函數(shù)FlashWindowEx的功能、定義及實(shí)現(xiàn)窗口閃爍的相關(guān)技巧,需要的朋友可以參考下
    2016-08-08
  • C#內(nèi)置泛型委托之Func委托

    C#內(nèi)置泛型委托之Func委托

    這篇文章介紹了C#內(nèi)置泛型委托之Func委托的用法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-03-03
  • 詳解如何在C#中使用投影(Projection)

    詳解如何在C#中使用投影(Projection)

    這篇文章主要介紹了詳解如何在C#中使用投影(Projection),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • C# 實(shí)現(xiàn)Table的Merge,Copy和Clone

    C# 實(shí)現(xiàn)Table的Merge,Copy和Clone

    這篇文章主要介紹了C# 實(shí)現(xiàn)Table的Merge,Copy和Clone,幫助大家更好的利用c#處理文件,感興趣的朋友可以了解下
    2020-12-12
  • C#正則表達(dá)式(Regex類)用法實(shí)例總結(jié)

    C#正則表達(dá)式(Regex類)用法實(shí)例總結(jié)

    正則表達(dá)式的主要作用是驗(yàn)證字符串的值是否滿足一定的規(guī)則,在頁(yè)面輸入數(shù)據(jù)驗(yàn)證方面的應(yīng)用比較多,下面這篇文章主要給大家介紹了關(guān)于C#正則表達(dá)式(Regex類)用法的相關(guān)資料,需要的朋友可以參考下
    2022-08-08
  • C#中哈希表(HashTable)用法實(shí)例詳解(添加/移除/判斷/遍歷/排序等)

    C#中哈希表(HashTable)用法實(shí)例詳解(添加/移除/判斷/遍歷/排序等)

    這篇文章主要介紹了C#中哈希表(HashTable)用法,簡(jiǎn)單講述了哈希表的原理并結(jié)合實(shí)例形式詳細(xì)分析了C#針對(duì)哈希表進(jìn)行添加、移除、判斷、遍歷、排序等操作的實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2016-06-06
  • Unity利用材質(zhì)自發(fā)光實(shí)現(xiàn)物體閃爍

    Unity利用材質(zhì)自發(fā)光實(shí)現(xiàn)物體閃爍

    這篇文章主要為大家詳細(xì)介紹了Unity利用材質(zhì)自發(fā)光實(shí)現(xiàn)物體閃爍,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-04-04
  • C#跨窗體操作(引用傳遞) 實(shí)例代碼

    C#跨窗體操作(引用傳遞) 實(shí)例代碼

    現(xiàn)在給大家介紹一種最簡(jiǎn)單的跨窗體操作,WinForm的窗體是一個(gè)類,C#的類是引用類型,那么我們應(yīng)該可以將WinForm窗體類進(jìn)行傳遞,那不就可以進(jìn)行操作了么?
    2013-03-03
  • C#枚舉類型與結(jié)構(gòu)類型實(shí)例解析

    C#枚舉類型與結(jié)構(gòu)類型實(shí)例解析

    這篇文章主要介紹了C#枚舉類型與結(jié)構(gòu)類型實(shí)例,需要的朋友可以參考下
    2014-07-07
  • 詳解c# 線程同步

    詳解c# 線程同步

    這篇文章主要介紹了c# 線程同步的相關(guān)資料,文中講解非常細(xì)致,示例代碼幫助大家更好的理解和學(xué)習(xí)c# 多線程,感興趣的朋友可以了解下
    2020-07-07

最新評(píng)論