Mementoパターン
状態を保存しておいて、復元できるようにしておく。
undo,redo,history,snapshot
復元するためにインスタンスの内部情報を公開すると、カプセル化の破壊になるので、
インタフェースを使い分ける。
Originator(作成者):Gamer
自分の現在の状態を保存したいときにMementoをつくる。
以前のMementoを渡されると、その状態に戻る。
Memento(記念品):Memento
Originatorの情報を持っているが、誰にでも公開はしない。
広いインタフェース→オブジェクトを元に戻すために内部情報を得られるメソッド。Originatorだけが使える。
狭いインタフェース→Caretakerに見せるもの。
Caretaker(世話をする人):Main
Originatorの状態を保存したいときに、Originatorに伝える。
OriginatorはMementoをCaretakerに渡す。
CaretakerはMementoの狭いインタフェースしか使えないので、Mementoの内部情報をいじることはできない。
Memento.php
class Memento { private $money; private $fruits = []; function __construct($money) { $this->money = $money; } function getMoney() { return $this->money; } function addFruit($fruit) { $this->fruits[] = $fruit; } function getFruits() { return $this->fruits; } }
Gamer.php
class Gamer { private $money; private $fruits = []; private $fruitNames = ["夕張メロン","すいか","もも","なし"]; function __construct($money) { $this->money = $money; } function getMoney() { return $this->money; } function bet() { $dice = rand(1, 6); if ($dice == 1) { $this->money += 100; echo "所持金が増えました\n"; } else if ($dice == 2) { $this->money /= 2; echo "所持金が半分になりました\n"; } else if ($dice == 6) { $f = $this->getFruit(); echo "フルーツ(" . $f . ")をもらいました\n"; $this->fruits[] = $f; } else { echo "何も起こりませんでした\n"; } } function createMemento() { $m = new Memento($this->money); foreach ($this->fruits as $f) { if (strpos($f, "おいしい") !== false) { $m->addFruit($f); } } return $m; } function restoreMemento(Memento $memento) { $this->money = $memento->getMoney(); $this->fruits = $memento->getFruits(); } function toString() { return "[money = " . $this->money . ", fruits = " . implode(",", $this->fruits) . "]"; } private function getFruit() { $prefix = rand(0, 1) ? "おいしい" : ""; return $prefix . $this->fruitNames[rand(0, count($this->fruitNames) - 1)]; } }
Main.php
require "../autoload.php"; $gamer = new Gamer(100); $memento = $gamer->createMemento(); for ($i=1;$i<=100;$i++) { echo $i . ":" . $gamer->toString() . "\n"; $gamer->bet(); echo "所持金:" . $gamer->getMoney() . "\n"; if ($gamer->getMoney() > $memento->getMoney()) { echo " (保存)\n"; $memento = $gamer->createMemento(); } else if ($gamer->getMoney() < $memento->getMoney() / 2) { echo " (復元)\n"; $gamer->restoreMemento($memento); } sleep(1); }