圖解Java設計模式之備忘錄模式

来源:https://www.cnblogs.com/haizai/archive/2020/04/02/12622623.html
-Advertisement-
Play Games

圖解Java設計模式之備忘錄模式 游戲角色狀態恢復問題 傳統方案解決游戲角色恢復 傳統的方式的問題分析 備忘錄模式基本介紹 備忘錄模式原理類圖 游戲角色恢復狀態實例 備忘錄模式的註意事項和細節 游戲角色狀態恢復問題 游戲角色有攻擊力和防禦力,在大戰Boss前保存自身的狀態(攻擊力和防禦力),當大戰B ...


圖解Java設計模式之備忘錄模式

 

游戲角色狀態恢復問題

游戲角色有攻擊力和防禦力,在大戰Boss前保存自身的狀態(攻擊力和防禦力),當大戰Boss後攻擊力和防禦力下降,從備忘錄對象恢復到大戰前的狀態。

傳統方案解決游戲角色恢復

在這裡插入圖片描述

傳統的方式的問題分析

1)一個對象,就對應一個保存對象狀態的對象,這樣當我們游戲的對象很多時,不利於管理,開銷很大。
2)傳統的方式是簡單的做備份,new出另外一個對象出來,再把需要備份的數據放到這個新對象,但這就暴露了對象內部的細節

備忘錄模式基本介紹

1)備忘錄模式(Memento Pattern)在不破壞封裝性的前提下,捕獲一個對象的內部狀態,併在該對象之外保存這個狀態。這樣以後就可將該對象恢復到原先保存的狀態。
2)可以這裡理解備忘錄模式 :現實生活中的備忘錄是用來記錄某些要去做的事情,或者是記錄已經達成的共同意見的事情,以防忘記。而在軟體層面,備忘錄模式有著相同的含義,備忘錄對象主要用來記錄一個對象某種狀態,或者某些數據,當要做回退時,可以從備忘錄對象里獲取原來的數據進行恢復操作。
3)備忘錄模式屬於行為型模式。

備忘錄模式原理類圖

在這裡插入圖片描述
對原理類圖的說明 :
1)originator :對象(需要保存狀態的對象)
2)Memento :備忘錄對象,負責保存好記錄,即Originator內部狀態
3)Caretaker :守護著對象,負責保存多個備忘錄對象,使用集合管理,提高效率
4)說明 :如果希望保存多個originator對象的不同時間的狀態,也可以,只需要HashMap<String, 集合>

package com.example.demo.memento.theory;

public class Memento {
	
	private String state;
	
	public Memento(String state) {
		super();
		this.state = state;
	}

	public String getState() {
		return state;
	}

}
package com.example.demo.memento.theory;

import java.util.ArrayList;
import java.util.List;

public class Caretaker {
	
	/**
	 * 在list 集合中會有很多的備忘錄對象
	 */
	private List<Memento> mementos = new ArrayList<Memento>();
	
	public void add(Memento memento) {
		mementos.add(memento);
	}
	
	/**
	 * 獲取到第index個Originator 的 備忘錄對象(即保存狀態)
	 * @param index
	 * @return
	 */
	public Memento get(int index) {
		return mementos.get(index);
	}
}
package com.example.demo.memento.theory;

public class Originator {
	
	/**
	 * 狀態信息
	 */
	private String state;

	public String getState() {
		return state;
	}

	public void setState(String state) {
		this.state = state;
	}
	
	// 編寫一個方法,可以保存一個狀態對象 Memento
	// 因此編寫一個方法,返回Memento
	public Memento saveStateMemento() {
		return new Memento(state);
	}
	
	public void getStateFromMemento(Memento memento) {
		state = memento.getState();
	}

}
package com.example.demo.memento.theory;

public class Client {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Originator originator = new Originator();
		Caretaker caretaker = new Caretaker();
		originator.setState(" 狀態1 攻擊力100 ");
		// 保存當前狀態
		caretaker.add(originator.saveStateMemento());
		
		originator.setState(" 狀態2 攻擊力80 ");
		// 保存當前狀態
		caretaker.add(originator.saveStateMemento());
		
		originator.setState(" 狀態3 攻擊力50 ");
		// 保存當前狀態
		caretaker.add(originator.saveStateMemento());
		System.out.println(" 現在狀態是 " + originator.getState());
		
		// 希望得到狀態1,將originator 恢復到狀態1
		originator.getStateFromMemento(caretaker.get(0));
		System.out.println(" 恢復狀態 1");
		System.out.println("當前的狀態是 = " + originator.getState());
	}

}

游戲角色恢復狀態實例

1)應用實例要求
游戲角色有攻擊力和防禦力,在大戰Boss前保存自身的狀態(攻擊力和防禦力),當大戰Boss後攻擊力和防禦力下降,從備忘錄對象恢復到大戰前的狀態
2)類圖
在這裡插入圖片描述

package com.example.demo.memento.game;

public class Memento {
	
	/**
	 * 攻擊力
	 */
	private int vit;

	/**
	 * 防禦力
	 */
	private int def;

	public Memento(int vit, int def) {
		super();
		this.vit = vit;
		this.def = def;
	}

	public int getVit() {
		return vit;
	}

	public void setVit(int vit) {
		this.vit = vit;
	}

	public int getDef() {
		return def;
	}

	public void setDef(int def) {
		this.def = def;
	}
}
package com.example.demo.memento.game;

import java.util.List;
import java.util.Map;

import javax.activation.MailcapCommandMap;

/**
 * 守護者對象,保存游戲角色的狀態
 * @author zhaozhaohai
 *
 */
public class Caretaker {

	/**
	 * 如果只保存一次狀態
	 */
	private Memento memento;
	/**
	 * 對GameRole 保存多次狀態
	 */
	private List<Memento> list;
	/**
	 * 對多個游戲角色保存多個狀態
	 */
	private Map<String, List<Memento>> rMap;
	public Memento getMemento() {
		return memento;
	}
	public void setMemento(Memento memento) {
		this.memento = memento;
	}
	
}
package com.example.demo.memento.game;

public class GameRole {
	
	private int vit;
	
	private int def;
	
	/**
	 * 創建Memento,即根據當前的狀態得到Memento
	 * @return
	 */
	public Memento createMemento() {
		return new Memento(vit, def);
	}
	
	/**
	 * 從備忘錄對象,恢復GameRole的狀態
	 * @param memento
	 */
	public void recoverGameRoleFromMemento(Memento memento) {
		this.vit = memento.getVit();
		this.def = memento.getDef();
	}
	
	/**
	 * 顯示當前游戲角色的狀態
	 */
	public void display() {
		System.out.println("游戲角色當前的攻擊力 :" + this.vit + " 防禦力 : " + this.def);
	}

	public int getVit() {
		return vit;
	}

	public void setVit(int vit) {
		this.vit = vit;
	}

	public int getDef() {
		return def;
	}

	public void setDef(int def) {
		this.def = def;
	}
	
	

}
package com.example.demo.memento.game;

public class Client {
	public static void main(String[] args) {
		//創建游戲角色
		GameRole gameRole = new GameRole(); 
		gameRole.setVit(100); 
		gameRole.setDef(100);
		System.out.println("和 boss 大戰前的狀態");
		gameRole.display();
		//把當前狀態保存 caretaker
		Caretaker caretaker = new Caretaker(); 
		caretaker.setMemento(gameRole.createMemento());
		System.out.println("和 boss 大戰~~~"); 
		gameRole.setDef(30); 
		gameRole.setVit(30);
		gameRole.display(); 
		System.out.println("大戰後,使用備忘錄對象恢復到站前");
		gameRole.recoverGameRoleFromMemento(caretaker.getMemento()); 
		System.out.println("恢復後的狀態");
		gameRole.display();
	}
}

備忘錄模式的註意事項和細節

1)給用戶提供了一種可以恢復狀態的機制,可以使用戶能過比較方便地回到某個歷史的狀態。
2)實現了信息的封裝,使得用戶不需要關心狀態的保存細節。
3)如果類的成員變數過多,勢必會占用比較大的資源,而且每一次保存都會消耗一定的記憶體,這個需要註意。
4)使用的應用場景 :1、後悔藥;2、打游戲時的存檔;3、Windows里的ctri + z。4、IE中的後退。4、資料庫的事務管理。
5)為了節約記憶體,備忘錄模式可以和原型模式陪著使用。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 選擇排序 + 代碼 + 運行效果 冒泡排序 + 代碼 + 運行效果 ...
  • 可視化工具D3.js,就不贅述他的簡介與下載了,官網上看,直接上教程: 可視化工具D3.js教程 入門 (第一章)—— hello world 可視化工具D3.js教程 入門 (第二章)—— 選擇元素與數據綁定 可視化工具D3.js教程 入門 (第三章)—— 理解 Update Enter Exit ...
  • 還是那句話,有時候你可能沒有Jquery可用,那麼我們可以借用原生JS中Dom對象的新方法:querySelector和querySelectorAll 實現Jquery篩選器同樣的篩選節點的效果,下麵列舉一些示例: 1-直接從頁面中篩選元素: id選擇器: var myidDom=document ...
  • 有時候,我們無法藉助熟悉的jquery發起請求,原生JS里是支持fetch函數的,這是個高度封裝的方法,幫助我們做了很多底層的封裝,下麵列舉一些發起請求的示例: 1-發起Get請求: //httpGet請求 var httpGet = async function (getUrl) { var op ...
  • 偶然間遇到,需要在JS中解決類似於C#中的線程休眠問題,JS有Promise對象,可以幫助我們實現這一點,網上有很多類似文章,我這裡列舉一個使用示例: 定義休眠方法--使用Promise創建一個非同步可等待的方法: //設置JS休眠一定時間後執行的動作 var sleep = function (mi ...
  • 一、GOF 23種設計模式簡介 設計模式其實是一門藝術。設計模式來源於生活,不要為了套用設計模式而去使用設計模式。設計模式是在我們迷茫時提供的一種解決問題的方案,或者說用好設計模式可以防範於未然。自古以來,在我們人生迷茫時,我們往往都會尋求幫助,或上門咨詢,或查經問典。就在幾千年前,孔夫子就教給了我 ...
  • 前言 本文章針對Java課程前三次PTA作業進行總結 一.作業過程總結 1.總結三次作業之間的知識迭代關係:關於前三次作業之間的迭代關係,第一次作業主要是關於Java的最基礎的練習,演算法都可以直接再main函數裡面實現,初步瞭解Java的一些基本的操作,輸入輸出,至於其它語句和C語言都是一樣的。 第 ...
  • 圖解Java設計模式之解釋器模式 四則運算問題 傳統方案解決四則運算問題分析 解釋器模式基本介紹 解釋器模式來實現四則 解析器模式在Spring框架中的源碼分析 解釋器模式的註意事項和細節 四則運算問題 通過解釋器模式來實現四則運算,如計算 a + b + c 的值,具體要求1)先輸入表達式的形式, ...
一周排行
    -Advertisement-
    Play Games
  • Dapr Outbox 是1.12中的功能。 本文只介紹Dapr Outbox 執行流程,Dapr Outbox基本用法請閱讀官方文檔 。本文中appID=order-processor,topic=orders 本文前提知識:熟悉Dapr狀態管理、Dapr發佈訂閱和Outbox 模式。 Outbo ...
  • 引言 在前幾章我們深度講解了單元測試和集成測試的基礎知識,這一章我們來講解一下代碼覆蓋率,代碼覆蓋率是單元測試運行的度量值,覆蓋率通常以百分比表示,用於衡量代碼被測試覆蓋的程度,幫助開發人員評估測試用例的質量和代碼的健壯性。常見的覆蓋率包括語句覆蓋率(Line Coverage)、分支覆蓋率(Bra ...
  • 前言 本文介紹瞭如何使用S7.NET庫實現對西門子PLC DB塊數據的讀寫,記錄了使用電腦模擬,模擬PLC,自至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1.Windows環境下鏈路層網路訪問的行業標準工具(WinPcap_4_1_3.exe)下載鏈接:http ...
  • 從依賴倒置原則(Dependency Inversion Principle, DIP)到控制反轉(Inversion of Control, IoC)再到依賴註入(Dependency Injection, DI)的演進過程,我們可以理解為一種逐步抽象和解耦的設計思想。這種思想在C#等面向對象的編 ...
  • 關於Python中的私有屬性和私有方法 Python對於類的成員沒有嚴格的訪問控制限制,這與其他面相對對象語言有區別。關於私有屬性和私有方法,有如下要點: 1、通常我們約定,兩個下劃線開頭的屬性是私有的(private)。其他為公共的(public); 2、類內部可以訪問私有屬性(方法); 3、類外 ...
  • C++ 訪問說明符 訪問說明符是 C++ 中控制類成員(屬性和方法)可訪問性的關鍵字。它們用於封裝類數據並保護其免受意外修改或濫用。 三種訪問說明符: public:允許從類外部的任何地方訪問成員。 private:僅允許在類內部訪問成員。 protected:允許在類內部及其派生類中訪問成員。 示 ...
  • 寫這個隨筆說一下C++的static_cast和dynamic_cast用在子類與父類的指針轉換時的一些事宜。首先,【static_cast,dynamic_cast】【父類指針,子類指針】,兩兩一組,共有4種組合:用 static_cast 父類轉子類、用 static_cast 子類轉父類、使用 ...
  • /******************************************************************************************************** * * * 設計雙向鏈表的介面 * * * * Copyright (c) 2023-2 ...
  • 相信接觸過spring做開發的小伙伴們一定使用過@ComponentScan註解 @ComponentScan("com.wangm.lifecycle") public class AppConfig { } @ComponentScan指定basePackage,將包下的類按照一定規則註冊成Be ...
  • 操作系統 :CentOS 7.6_x64 opensips版本: 2.4.9 python版本:2.7.5 python作為腳本語言,使用起來很方便,查了下opensips的文檔,支持使用python腳本寫邏輯代碼。今天整理下CentOS7環境下opensips2.4.9的python模塊筆記及使用 ...