[toc]
## 舉個例子
> 用過錘子手機的閃念膠囊APP嗎?
> 在你狀態好, 有靈感的時候, 把想法記下來
> 等你有時間寫作的時候, 即使不在狀態, 依然"記得"那些好想法...
## 代碼示例
```php
<?php
// 工程師
class Engineer {
private $name;
private $workItems;
public function __construct($name) {
$this->name = $name;
$this->workItems = [];
}
public function addWorkItem($item) {
array_push($this->workItems, $item);
}
public function forget() {
$this->workItems = [];
echo $this->name . "工作太忙了,都忘記要做什么了!";
}
public function writeTodoList() {
$todoList = new TodoList();
foreach ($this->workItems as $item) {
$todoList->writeWorkItem($item);
}
return $todoList;
}
public function retrospect($todoList) {
$this->workItems = $todoList->getWorkItems();
echo $this->name . "想起要做什么了!";
}
public function showWorkItem() {
if (count($this->workItems)) {
echo $this->name . "的工作項:" . PHP_EOL;
foreach ($this->workItems as $key => $value) {
echo strval($key + 1) . '-->' . $this->workItems[$key] . ';' . PHP_EOL;
}
} else {
echo $this->name . "暫無工作項!" . PHP_EOL;
}
}
}
// 工作項
class TodoList {
private $workItems;
public function __construct() {
$this->workItems = [];
}
public function writeWorkItem($item) {
array_push($this->workItems, $item);
}
public function getWorkItems() {
return $this->workItems;
}
}
// TodoList管理類
class TodoListCaretaker {
private $todoList;
public function __construct() {
$this->todoList = null;
}
public function setTodoList($todoList) {
$this->todoList = $todoList;
}
public function getTodoList() {
return $this->todoList;
}
}
// 測試代碼
$tony = new Engineer("Tony");
$tony->addWorkItem("解決線上部分用戶因昵稱太長而無法顯示全的問題");
$tony->addWorkItem("完成PDF的解析");
$tony->addWorkItem("在閱讀器中顯示PDF第一頁的內容");
$tony->showWorkItem();
$caretaker = new TodoListCaretaker();
$caretaker->setTodoList($tony->writeTodoList());
echo PHP_EOL;
$tony->forget();
$tony->showWorkItem();
echo PHP_EOL;
$tony->retrospect($caretaker->getTodoList());
$tony->showWorkItem();
```
```
D:\soft\php72\php.exe D:\project\php_dp\index.php
Tony的工作項:
1-->解決線上部分用戶因昵稱太長而無法顯示全的問題;
2-->完成PDF的解析;
3-->在閱讀器中顯示PDF第一頁的內容;
Tony工作太忙了,都忘記要做什么了!Tony暫無工作項!
Tony想起要做什么了!Tony的工作項:
1-->解決線上部分用戶因昵稱太長而無法顯示全的問題;
2-->完成PDF的解析;
3-->在閱讀器中顯示PDF第一頁的內容;
Process finished with exit code 0
```
## 什么是備忘模式?
> 在不破壞內部結構的前提下捕獲一個對象的內部狀態,這樣便可在以后將該對象恢復到原先保存的狀態。
1. 備忘錄模式的最大功能就是做備份,可以保存對象的一個狀態作為備份,這樣便可讓對象在將來的某一時刻恢復到之前保存的狀態。
2. 如同游戲中“死”了的英雄可以滿血復活一樣
3. 再比如很多電器(如電視、冰箱)都有恢復出廠設置的功能
4. 人生沒有彩排,但程序卻可以讓你無數次回放!

## 設計要點
1. **發起人(Originator)**: 需要進行備份的對象。
1. **備忘錄(Memento)**: 備份的狀態,即一個備份的存檔。
1. **備忘錄管理者(Caretaker)**: 備份存檔的管理者,由它負責與發起人的交互。
## 優缺點
**備忘錄模式的優點**:
1. 給用戶提供了一種可以恢復狀態的機制,使得用戶能夠比較方便地回到某個歷史的狀態。
1. 實現了信息的封裝,用戶不需要關心狀態的保存細節。
**備忘錄模式的缺點**:
1. 如果類的成員變量過多,勢必會占用比較大的資源,
2. 每一次保存都會消耗一定的內存,此時可以限制保存的最大次數。
## 應用場景
1. 需要保存/恢復對象的狀態或數據,如游戲的存檔、虛擬機的快照。
1. 需要實現撤銷、恢復功能的場景,如 Word 中的 Ctrl+Z、Ctrl+Y 功能,DOS 命令行或 Linux 終端的命令記憶功能。
1. 提供一個可回滾的操作,如數據庫的事務管理。