简介
允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态,该状态保存在对象之外,这样就可以不破坏原有对象的封装性了。
角色
-
Originator 原发器
即需要被保存状态的类
-
抽象 Memento 备忘录类
定义备忘录基本接口
可以看做成是快照 Snapshot
-
具体 Memento 备忘录类
实现接口
-
Caretaker 负责人
即连接Originator和Memento的类,维护一个Memento队列,通过操作队列实现undo redo的操作
类图
图中,ConcreteOriginator通过save方法,生成一个Memento,Caretaker 的history属性保存这些Memento,实现undo操作。
代码
class Originator
{
private $state;
public function __construct(string $state)
{
$this->state = $state;
echo "Originator: My initial state is: {$this->state}\n";
}
public function doSomething(): void
{
echo "Originator: I'm doing something important.\n";
$this->state = $this->generateRandomString(30);
echo "Originator: and my state has changed to: {$this->state}\n";
}
private function generateRandomString(int $length = 10): string
{
return substr(
str_shuffle(
str_repeat(
$x = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
ceil($length / strlen($x))
)
),
1,
$length
);
}
public function save(): Memento
{
return new ConcreteMemento($this->state);
}
public function restore(Memento $memento): void
{
$this->state = $memento->getState();
echo "Originator: My state has changed to: {$this->state}\n";
}
}
interface Memento
{
public function getName(): string;
public function getDate(): string;
}
class ConcreteMemento implements Memento
{
private $state;
private $date;
public function __construct(string $state)
{
$this->state = $state;
$this->date = date('Y-m-d H:i:s');
}
public function getState(): string
{
return $this->state;
}
public function getName(): string
{
return $this->date . " / (" . substr($this->state, 0, 9) . "...)";
}
public function getDate(): string
{
return $this->date;
}
}
class Caretaker
{
private $mementos = [];
private $originator;
public function __construct(Originator $originator)
{
$this->originator = $originator;
}
public function backup(): void
{
echo "\nCaretaker: Saving Originator's state...\n";
$this->mementos[] = $this->originator->save();
}
public function undo(): void
{
if (!count($this->mementos)) {
return;
}
$memento = array_pop($this->mementos);
echo "Caretaker: Restoring state to: " . $memento->getName() . "\n";
try {
$this->originator->restore($memento);
} catch (\Exception $e) {
$this->undo();
}
}
public function showHistory(): void
{
echo "Caretaker: Here's the list of mementos:\n";
foreach ($this->mementos as $memento) {
echo $memento->getName() . "\n";
}
}
}
$originator = new Originator("Super-duper-super-puper-super.");
$caretaker = new Caretaker($originator);
$caretaker->backup();
$originator->doSomething();
$caretaker->backup();
$originator->doSomething();
$caretaker->backup();
$originator->doSomething();
echo "\n";
$caretaker->showHistory();
echo "\nClient: Now, let's rollback!\n\n";
$caretaker->undo();
echo "\nClient: Once more!\n\n";
$caretaker->undo();
output:
Originator: My initial state is: Super-duper-super-puper-super.
Caretaker: Saving Originator's state...
Originator: I'm doing something important.
Originator: and my state has changed to: uDdcJyRkbMEFqaKnpHiYQtrzWjXPVI
Caretaker: Saving Originator's state...
Originator: I'm doing something important.
Originator: and my state has changed to: YrymDJvtFqlwGpMuCNXadsQonIVPzR
Caretaker: Saving Originator's state...
Originator: I'm doing something important.
Originator: and my state has changed to: pOuLBUelsmFRkKrbhAGfqzTtQXjnNH
Caretaker: Here's the list of mementos:
2023-06-28 01:51:01 / (Super-dup...)
2023-06-28 01:51:01 / (uDdcJyRkb...)
2023-06-28 01:51:01 / (YrymDJvtF...)
Client: Now, let's rollback!
Caretaker: Restoring state to: 2023-06-28 01:51:01 / (YrymDJvtF...)
Originator: My state has changed to: YrymDJvtFqlwGpMuCNXadsQonIVPzR
Client: Once more!
Caretaker: Restoring state to: 2023-06-28 01:51:01 / (uDdcJyRkb...)
Originator: My state has changed to: uDdcJyRkbMEFqaKnpHiYQtrzWjXPVI
Top comments (0)