[Python設計模式] 第18章 遊戲角色備份——備忘錄模式

github地址:https://github.com/cheesezh/python_design_patternspython

題目

用代碼模擬如下場景,一個遊戲角色有生命力,攻擊力,防護力等數據,在打Boss先後的數據值會發生變化,若是玩家挑戰Boss失敗,咱們容許玩家能夠將遊戲數據恢復到與Boss決鬥以前的狀態。git

基礎版本

class GameRole():
    
    def __init__(self):
        self.vitality = 0
        self.attack = 0
        self.defense = 0
        
    def state_display(self):
        print("當前角色狀態:")
        print("體力:",self.vitality)
        print("攻擊:",self.attack)
        print("防護:",self.defense)
        
    def get_init_state(self):
        """
        從服務器或者本地磁盤加載初始狀態
        """
        self.vitality = 100
        self.attack = 100
        self.defense = 100
        
    def fight(self):
        """
        與Boss決鬥,數據損耗爲0
        """
        self.vitality = 0
        self.attack = 0
        self.defense = 0
        
        
def main():
    mario = GameRole()  
    mario.get_init_state()  # 大戰Boss前,獲取初始角色狀態
    mario.state_display()
    
    backup = GameRole()  # 保存遊戲進度
    backup.vitality = mario.vitality
    backup.attack = mario.attack
    backup.defense = mario.defense
    
    mario.fight()  # 大戰Boss
    mario.state_display()
    
    mario.vitality = backup.vitality  # 讀取進度,從新來過
    mario.attack = backup.attack
    mario.defense = backup.defense
    
    mario.state_display()
    
main()
當前角色狀態:
體力: 100
攻擊: 100
防護: 100
當前角色狀態:
體力: 0
攻擊: 0
防護: 0
當前角色狀態:
體力: 100
攻擊: 100
防護: 100

點評

主要問題在於客戶端調用:github

  1. 遊戲角色細節暴露給了客戶端,客戶端須要知道遊戲角色的生命力,攻擊力,防護力等細節;
  2. 客戶端還要對遊戲角色進行備份;
  3. 若是之後增長「魔法值」或者修改現有數據,都要更改客戶端;
  4. 恢復角色的過程也存在一樣問題;

備忘錄模式

備忘錄模式,在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象以外保存這個狀態。這樣之後就可將該對象恢復到原先保存的狀態。主要包括三種類:服務器

  • 發起人(Originator):負責建立一個備忘錄Memento,用以記錄當前時刻它的內部狀態,並可以使用備忘錄恢復內部狀態。Originator能夠根據須要決定Memento存儲Originator的哪些內部狀態;
  • 備忘錄(Memento):負責存儲Originator對象的內部狀態,並可防止Originator之外的其餘對象訪問備忘錄Memento。備忘錄有兩個接口,Caretaker只能看到備忘錄的窄接口,它只能將備忘錄傳遞給其餘對象。Originator能夠看到一個寬接口,容許它訪問返回到先前狀態的全部數據;
  • 管理者(Caretaker):負責保存好備忘錄Memento,不能對備忘錄的內容進行操做或檢查。

在題目的場景中,遊戲角色類至關於Originator,使用一樣的「遊戲角色」實例「backup」來作備忘錄,這在當須要保存所有信息時,是能夠考慮的,而用clone的方式來實現Memento的狀態保存多是更好的方法,可是這樣就至關於對上層應用開放了Originator的所有接口,這對於保存備份有時候並不合適。code

那麼當咱們不須要保存所有信息以備使用時,須要怎麼辦?當咱們須要保存的並非所有信息,而只是部分信息,那麼就應該有獨立的備忘錄類Memento,它只擁有須要保存的信息的屬性。對象

改進版本——備忘錄模式

class GameRole():
    
    def __init__(self):
        self.vitality = 0
        self.attack = 0
        self.defense = 0
        
    def state_display(self):
        print("當前角色狀態:")
        print("體力:",self.vitality)
        print("攻擊:",self.attack)
        print("防護:",self.defense)
        
    def get_init_state(self):
        """
        從服務器或者本地磁盤加載初始狀態
        """
        self.vitality = 100
        self.attack = 100
        self.defense = 100
        
    def fight(self):
        """
        與Boss決鬥,數據損耗爲0
        """
        self.vitality = 0
        self.attack = 0
        self.defense = 0
        
    def save_state(self):
        """
        新增「保存狀態」的方法
        """
        return RoleStateMemento(self.vitality, self.attack, self.defense)
    
    def recovery_state(self, memento):
        """
        新增「恢復狀態」的方法
        """
        self.vitality = memento.vitality
        self.attack = memento.attack
        self.defense = memento.defense
        

class RoleStateMemento():
    """
    遊戲角色狀態存儲箱
    """
    def __init__(self, vitality, attack, defense):
        self.vitality = vitality
        self.attack = attack
        self.defense = defense
        

class RoleStateCaretaker():
    """
    角色狀態管理者類
    """
    def __init__(self):
        self.memento = None
        

def main():
    mario = GameRole()
    mario.get_init_state()
    mario.state_display()
    
    state_admin = RoleStateCaretaker()
    state_admin.memento = mario.save_state()  # 遊戲角色的保存對客戶端是透明的
    
    mario.fight()
    mario.state_display()
    
    mario.recovery_state(state_admin.memento)  # 遊戲角色的恢復對客戶端是透明的
    mario.state_display()
    
main()
當前角色狀態:
體力: 100
攻擊: 100
防護: 100
當前角色狀態:
體力: 0
攻擊: 0
防護: 0
當前角色狀態:
體力: 100
攻擊: 100
防護: 100

點評

將須要保存的細節封裝在Memento類中,那一天要更改保存的細節也不用影響客戶端。接口

Memento模式比較適用於功能複雜的,但須要維護或記錄屬性歷史的類,或者須要保存的屬性只是衆多屬性中的一小部分時,Originator能夠根據保存的Memento信息還原到前一狀態。遊戲

命令模式也有相似的撤銷做用,若是在某個系統中使用命令模式時,須要實現命令的撤銷功能,那麼命令模式可使用備忘錄模式來存儲可撤銷操做的狀態。有時候一些對象的內部信息必須保存在對象之外的地方,可是必需要由對象本身讀取,這時,使用備忘錄能夠把複雜的對象內部信息對其餘的對象屏蔽起來,從而能夠恰當的保持封裝的邊界。get

當角色的狀態改變的時候,有可能這個狀態無效,這時候就可使用暫時存儲起來的備忘錄將狀態復原。it

相關文章
相關標籤/搜索