52 條 SQL 語句效能優化策略
2020年11月29日15:25:07
備忘錄模式
引子
曾經有一份真摯的愛情擺在我的面前,但是我沒有珍惜,等我失去後才後悔莫及,塵世間最痛苦的事情莫過於此。
如果上天能夠給我一個再來一次的機會,我會對那個女孩說三個字:我愛你。
如果非要在這份愛上加一個期限,我希望是一萬年!
——至尊寶
定義
Without violating encapsulation, capture and externalize an object's internal state so that the object can be restored to this state later. ——《Design Patterns: Elements of Reusable Object-Oriented Software》
備忘錄模式(memento pattern),在不破壞封裝型的前提下,獲取並儲存一個物件的內部狀態,以便以後物件可以恢復到這個狀態。——《設計模式:可複用面向物件軟體的基礎》
圖示
備忘錄模式結構圖:
結構圖顯示了備忘錄模式的物件角色有三,一是發起人(Originator), 二是備忘錄(Memento),三是管理者(Caretaker)。
備忘錄模式流程圖:
流程圖展示了備忘錄模式的工作流程:
1、管理者(Caretaker)呼叫發起人(Originator)createMemento建立備忘錄儲存狀態
2、管理者呼叫發起人的setMemento從備忘錄獲取備份的狀態恢復
角色
發起人(Originator):從結構圖中的兩個方法createMemento和setMemento可以看出,發起人負責的是建立一個備忘錄Memento,以及在需要的時候使用Memento恢復自己的內部狀態。發起人可以根據需要決定儲存和恢復哪些內部狀態。
備忘錄(Memento):負責存在發起人(Originator)物件的內部狀態,並可防止Originator以外的其他物件訪問備忘錄(Memento)。備忘錄有兩個介面,Caretaker只能看到備忘錄的窄介面,它只能將備忘錄傳遞給其他物件;Originator能夠看到一個寬介面,允許他訪問返回到先前狀態所需的所有資料。怎麼做?Memento作為Originator的內部類就是可以實現了。
管理者(Caretaker):負責儲存好備忘錄,不能對備忘錄的內容進行操作或檢查。
程式碼示例
故事背景:
小時候,總想著長大,但是誰知道長大後一點有不好玩,朝九晚九。
我想玩電視劇回到年輕的劇情,讓我好好感受在春天放牛,夏天放鴨,秋天抓魚,冬天等小豬出生的日子。
有天我撿到一個相框,只要我把小時候的照片放到相框裡,我就可以回到小時候。
發起人(Originator)和備忘錄(Memento):
// 我
public class I {
private int age;
private String doingWhat;
public Photo createPhoto() {
return new Photo(this.age, this.doingWhat);
}
public void backToThePast(Photo photo) {
this.age = photo.getAge();
this.doingWhat = photo.getDoingSomething();
System.out.println("時光倒流,我現在是" + age + "歲,可以:" + doingWhat);
}
public void setAge(int age) {
this.age = age;
}
public void setDoingWhat(String doingWhat) {
this.doingWhat = doingWhat;
}
public void print() {
System.out.println("我現在是" + age + "歲,可以:" + doingWhat);
}
// 照片(備忘錄)
public class Photo {
private int age;
private String doingWhat;
public Photo(int age, String doingWhat) {
this.age = age;
this.doingWhat = doingWhat;
}
private int getAge() {
return age;
}
private String getDoingSomething() {
return doingWhat;
}
}
}
作為備忘錄角色的照片(photo)是我(I)的內部類,對我(I)來說是擁有寬介面包含getAge、getDoingSomething等方法,當然你也可以加其他方法,而這些方法對於其他物件是不可見的。
管理者(Caretaker):
// 時光倒流相框
public class Frame {
private List<I.Photo> photoList = new ArrayList<>();
public I.Photo getPhoto(int i) {
return photoList.get(i);
}
public void add(I.Photo photo) {
photoList.add(photo);
}
}
測試類:
public class MementoPatternTest {
public static void main(String[] args) {
I i = new I();
Frame frame = new Frame();
i.setAge(12);
i.setDoingWhat("春天放牛,夏天放鴨,秋天抓魚,冬天等小豬出生");
i.print();
frame.add(i.createPhoto());
i.setAge(18);
i.setDoingWhat("唸書");
frame.add(i.createPhoto());
i.print();
i.setAge(25);
i.setDoingWhat("工作");
i.print();
i.backToThePast(frame.getPhoto(0));
}
}
測試結果圖:
使用場景
如果你需要建立物件狀態的快照來恢復物件之前的狀態時,你可以使用備忘錄模式。
如果直接訪問物件的狀態會破壞封裝,可以使用備忘錄模式。
優點
- 你可以在不破壞物件封裝情況的前提下建立物件狀態快照。
缺點
- 如果客戶端過於頻繁地建立備忘錄, 程式將消耗大量記憶體。
- 管理者必須完整跟蹤原發器的生命週期, 這樣才能銷燬棄用的備忘錄。一般來說是這樣的,但是Java有垃圾回收器,管理者不存在,備忘錄也會被自動回收。
總結
備忘錄模式,在不破壞封裝型的前提下,獲取並儲存一個物件的內部狀態,以便以後物件可以恢復到這個狀態。該模式有三個角色:發起人(Originator)、備忘錄(Memento)、管理者(caretaker)。發起人建立備忘錄和利用備忘錄恢復狀態,備忘錄儲存發起人狀態,管理者儲存備忘錄。
2020年11月29日21:48:47