1. 程式人生 > >JAVA中的備忘錄模式例項教程

JAVA中的備忘錄模式例項教程

原文連結  作者:Pankaj Kumar 譯者:f0tlo <[email protected]>

備忘錄模式是一種行為模式。備忘錄模式用於儲存物件當前狀態,並且在之後可以再次使用此狀態。備忘錄模式實現的方式需要保證,被儲存的物件狀態不能被物件從外部訪問,目的為了被儲存的這些物件狀態的完整性。

備忘錄模式通過兩個物件實現:Originator以及Caretaker。Originator類代表了其狀態能夠被儲存並被用於恢復之前的狀態,它使用內部類儲存物件的狀態。此內部類就被叫做備忘錄,注意此類是私有的,它不能被其他物件訪問。

Caretaker是一個幫助類,它的職責就是通過備忘錄幫助Originator儲存當前狀態或者恢復重建其之前的狀態。因為備忘錄是Originator的私有類,Caretaker不能訪問它,因此它作為一個物件被儲存在caretaker中。

現實中最好的例子是文字編輯器,它任何時候都存在已經輸入的資料,並且可以使用回退功能恢復之前的儲存(寫作)狀態。我們將實現相同功能並且提供一個任何時候都把輸入、存在內容到檔案中的工具集,此外,我們也能恢復上一個儲存(寫作)的狀態。為了簡單,此處沒用更實用任何寫入資料到檔案的IO操作。

Originator類

package com.journaldev.design.memento;

public class FileWriterUtil {

	private String fileName;
	private StringBuilder content;

	public FileWriterUtil(String file){
		this.fileName=file;
		this.content=new StringBuilder();
	}

	@Override
	public String toString(){
		return this.content.toString();
	}

	public void write(String str){
		content.append(str);
	}

	public Memento save(){
		return new Memento(this.fileName,this.content);
	}

	public void undoToLastSave(Object obj){
		Memento memento = (Memento) obj;
		this.fileName= memento.fileName;
		this.content=memento.content;
	}

	private class Memento{
		private String fileName;
		private StringBuilder content;

		public Memento(String file, StringBuilder content){
			this.fileName=file;
			//notice the deep copy so that Memento and FileWriterUtil content variables don't refer to same object
			this.content=new StringBuilder(content);
		}
	}
}

注意備忘錄的內部類及其儲存及恢復方法。現在實現Caretaker類

Caretaker類

package com.journaldev.design.memento;

public class FileWriterCaretaker {

	private Object obj;

	public void save(FileWriterUtil fileWriter){
		this.obj=fileWriter.save();
	}

	public void undo(FileWriterUtil fileWriter){
		fileWriter.undoToLastSave(obj);
	}
}

注意caretaker物件包含了整個物件形式的儲存狀態,因此它既不能修改被儲存物件又對其結構未知。

備忘錄測試類

完整一個簡單地測試程式

package com.journaldev.design.memento;

public class FileWriterClient {

	public static void main(String[] args) {

		FileWriterCaretaker caretaker = new FileWriterCaretaker();

		FileWriterUtil fileWriter = new FileWriterUtil("data.txt");
		fileWriter.write("First Set of Data\n");
		System.out.println(fileWriter+"\n\n");

		// lets save the file
		caretaker.save(fileWriter);
		//now write something else
		fileWriter.write("Second Set of Data\n");

		//checking file contents
		System.out.println(fileWriter+"\n\n");

		//lets undo to last save
		caretaker.undo(fileWriter);

		//checking file content again
		System.out.println(fileWriter+"\n\n");

	}

}

上述程式的輸出如下:

First Set of Data

First Set of Data
Second Set of Data

First Set of Data

此模式簡單易實現,但是需要注意的是備忘錄類只能被Originator物件訪問。在客戶端程式中,使用caretaker物件完成儲存或恢復originator物件的狀態。

另外,如果Originator物件有一些屬性不是不可變的,我們需要使用深拷貝或者克隆來避免資料的完整性問題。使用序列化來取得備忘錄模式的實現不失為一般方法,而不是為每一個物件建立一個自己的備忘錄實現。

此模式的缺點是, 如果Originator物件非常巨大,那麼備忘錄物件的大小也會被相應增大,因而需要更多的記憶體空間。