【PHPデザインパターン】17_Memento~スナップショットを取る
引用記事
この記事を書くきっかけになったブログです。
記事内の解説やソースコードは、こちらのブログと著者の公開リポジトリを参考にしています。
Do You PHP はてな〜[doyouphp][phpdp]PHPによるデザインパターン入門 - Memento~スナップショットを取る
概要
- 「memento」は「記憶」「思い出」のような意味。(同名の映画もありますね。)
- 「Snapshotパターン」とも呼ばれる。
- アンドゥ(Undo:やり直し)を実現する。
- ある時点のオブジェクトの状態を別のオブジェクトとして保存しておき、状態が変化した場合でも、その時の状態に戻すことを可能にする。
- 状態を生成するクラスとその履歴の管理をするクラスを分離する。
構成要素
Mementoクラス
- Originatorオブジェクトの記憶を保持する記憶用クラス。
- 厳密には、Originator以外のオブジェクトによってアクセスさせないようにする必要がある。
- PHPには「特定のクラスだけにアクセスを許可する」といった制御機構は存在しないため、本来のMementoパターンの構造を若干変更する必要がある。
Originatorクラス
- オブジェクトの内部状態を保存される側のクラス。
- 内部状態をMementoオブジェクトに詰め込み、それを返すメソッドを持つ。
Caretakerクラス
- Mementoオブジェクトを管理するクラス
実演
処理の流れ
- addボタンで入力したコメントを登録する。
- saveボタンで今までaddしたコメントのスナップショットが登録され、restoreボタンでその状態を呼び戻すことができる。
- スナップショットは
DataSnapshotクラス
で保持し、DataSnapshot型オブジェクトはDataクラス
のメソッドで生成する。そのオブジェクトをDataCaretakerクラス
でセッションとして保管する。
- スナップショットを呼び戻したい場合は、DataCaretakerクラスからセッションデータ(DataSnapshot型オブジェクト)へアクセスし、Dataクラスのメソッドで表示する。
ファイル構造
MyMemento
├── Data.php
├── DataCaretaker.php
├── DataSnapshot.php
└── my_client.php
ソースコード
Mementoクラス
DataSnapshot.php
DataSnapshot.php
<?php
namespace DoYouPhp\PhpDesignPattern\Memento\MyMemento;
/**
* Mementoクラスに相当する
* Data型オブジェクトの内部状態を保管する
*/
class DataSnapshot
{
private $comment;
// Data型オブジェクトの内部状態を保管する
protected function __construct($comment)
{
$this->comment = $comment;
}
// 保管しているコメントを返す
protected function getComment()
{
return $this->comment;
}
}
Originatorクラス
Data.php
Data.php
<?php
namespace DoYouPhp\PhpDesignPattern\Memento\MyMemento;
use DoYouPhp\PhpDesignPattern\Memento\MyMemento\DataSnapshot;
/**
* Originatorクラスに相当する
* このオブジェクトの内部状態がDataSnapshotクラスに保管される
*/
final class Data extends DataSnapshot
{
private $comment;
// コンストラクタ
public function __construct()
{
$this->comment = array();
}
// MementoクラスであるDataSnapshot型インスタンスの生成
// コメントは、DataSnapshot型インスタンスのプロパティとしてセットする
public function takeSnapshot()
{
return new DataSnapshot($this->comment);
}
// DataSnapshot型インスタンスからコメントを復元する
// コメントは、Data型インスタンスのプロパティとしてセットされる
public function restoreSnapshot(DataSnapshot $snapshot)
{
$this->comment = $snapshot->getComment();
}
// コメントを追加する
// コメントは、Data型インスタンスのプロパティとしてセットされる
public function addComment($comment)
{
$this->comment[] = $comment;
}
// コメントを呼び出す
public function getComment()
{
return $this->comment;
}
}
Caretakerクラス
DataCaretaker.php
DataCaretaker.php
<?php
namespace DoYouPhp\PhpDesignPattern\Memento\MyMemento;
/**
* Caretakerクラスに相当する
* DataSnapshot型オブジェクトを管理する
*/
class DataCaretaker
{
private $snapshot;
// コンストラクタ
// セッションがなければ、セッションを開始する
public function __construct()
{
if (!isset($_SESSION)) {
session_start();
}
}
// $snapshotをセッションとして保管
public function setSnapshot($snapshot)
{
$this->snapshot = $snapshot;
$_SESSION['snapshot'] = $this->snapshot;
}
// セッション($snapshot)があれば返す
public function getSnapshot()
{
return (isset($_SESSION['snapshot']) ? $_SESSION['snapshot'] : null);
}
}
Clientクラス
my_client.php
my_client.php
<?php
namespace DoYouPhp\PhpDesignPattern\Memento\MyMemento;
require dirname(__DIR__).'/../vendor/autoload.php';
use DoYouPhp\PhpDesignPattern\Memento\MyMemento\Data;
use DoYouPhp\PhpDesignPattern\Memento\MyMemento\DataCaretaker;
// DataCaretakerクラスのコンストラクタで、セッションが開始される
$caretaker = new DataCaretaker();
// セッションがあればセッション、なければData型インスタンスをセット
$data = isset($_SESSION['data']) ? $_SESSION['data'] : new Data();
// postメソッドでボタンが押されたか確認する
$mode = (isset($_POST['mode']) ? $_POST['mode'] : null);
// 押されたボタンにより処理を分岐する
switch ($mode) {
case 'add':
// コメントをData型インスタンスに登録する
$data->addComment((isset($_POST['comment']) ? $_POST['comment'] : ''));
break;
case 'save':
// コメントのスナップショットを取り、保存する
// addされたコメントをDataSnapshot型インスタンスにセットしている
// それを引数にして、DataCaretaker型インスタンスにセッションとしてスナップショットを保管する
$caretaker->setSnapshot($data->takeSnapshot());
echo 'データを保存しました!'.'<br>'."\n";
break;
case 'restore':
// 保存したスナップショットを取得しコメントを復元する
// スナップショットはセッションとして保管されている
$data->restoreSnapshot($caretaker->getSnapshot());
echo 'データを復元しました!'.'<br>'."\n";
break;
case 'clear':
// Data型インスタンスを初期化する
// この時点では、セッションはまだ生きている状態
$data = new Data();
}
// 登録したコメントを取得し、表示する
// add, save, clearは表示される内容がそれぞれ異なる
echo '今までのコメント'.'<br>'."\n";
if (is_object($data)) {
echo '<ul>';
foreach ($data->getComment() as $comment) {
echo '<li>'.$comment.'</li>';
}
echo '</ul>';
}
// 次のアクセスで使うデータをセッションに保存する
$_SESSION['data'] = $data;
?>
<!-- 入力フォーム -->
<form action="" method="post">
コメント:<input type="text" name="comment"><br>
<input type="submit" name="mode" value="add">
<input type="submit" name="mode" value="save">
<input type="submit" name="mode" value="restore">
<input type="submit" name="mode" value="clear">
</form>
処理の流れ
- addボタンで入力したコメントを登録する。
- saveボタンで今までaddしたコメントのスナップショットが登録され、restoreボタンでその状態を呼び戻すことができる。
- スナップショットは
DataSnapshotクラス
で保持し、DataSnapshot型オブジェクトはDataクラス
のメソッドで生成する。そのオブジェクトをDataCaretakerクラス
でセッションとして保管する。 - スナップショットを呼び戻したい場合は、DataCaretakerクラスからセッションデータ(DataSnapshot型オブジェクト)へアクセスし、Dataクラスのメソッドで表示する。
ファイル構造
MyMemento
├── Data.php
├── DataCaretaker.php
├── DataSnapshot.php
└── my_client.php
ソースコード
Mementoクラス
DataSnapshot.php
DataSnapshot.php
<?php
namespace DoYouPhp\PhpDesignPattern\Memento\MyMemento;
/**
* Mementoクラスに相当する
* Data型オブジェクトの内部状態を保管する
*/
class DataSnapshot
{
private $comment;
// Data型オブジェクトの内部状態を保管する
protected function __construct($comment)
{
$this->comment = $comment;
}
// 保管しているコメントを返す
protected function getComment()
{
return $this->comment;
}
}
Originatorクラス
Data.php
Data.php
<?php
namespace DoYouPhp\PhpDesignPattern\Memento\MyMemento;
use DoYouPhp\PhpDesignPattern\Memento\MyMemento\DataSnapshot;
/**
* Originatorクラスに相当する
* このオブジェクトの内部状態がDataSnapshotクラスに保管される
*/
final class Data extends DataSnapshot
{
private $comment;
// コンストラクタ
public function __construct()
{
$this->comment = array();
}
// MementoクラスであるDataSnapshot型インスタンスの生成
// コメントは、DataSnapshot型インスタンスのプロパティとしてセットする
public function takeSnapshot()
{
return new DataSnapshot($this->comment);
}
// DataSnapshot型インスタンスからコメントを復元する
// コメントは、Data型インスタンスのプロパティとしてセットされる
public function restoreSnapshot(DataSnapshot $snapshot)
{
$this->comment = $snapshot->getComment();
}
// コメントを追加する
// コメントは、Data型インスタンスのプロパティとしてセットされる
public function addComment($comment)
{
$this->comment[] = $comment;
}
// コメントを呼び出す
public function getComment()
{
return $this->comment;
}
}
Caretakerクラス
DataCaretaker.php
DataCaretaker.php
<?php
namespace DoYouPhp\PhpDesignPattern\Memento\MyMemento;
/**
* Caretakerクラスに相当する
* DataSnapshot型オブジェクトを管理する
*/
class DataCaretaker
{
private $snapshot;
// コンストラクタ
// セッションがなければ、セッションを開始する
public function __construct()
{
if (!isset($_SESSION)) {
session_start();
}
}
// $snapshotをセッションとして保管
public function setSnapshot($snapshot)
{
$this->snapshot = $snapshot;
$_SESSION['snapshot'] = $this->snapshot;
}
// セッション($snapshot)があれば返す
public function getSnapshot()
{
return (isset($_SESSION['snapshot']) ? $_SESSION['snapshot'] : null);
}
}
Clientクラス
my_client.php
my_client.php
<?php
namespace DoYouPhp\PhpDesignPattern\Memento\MyMemento;
require dirname(__DIR__).'/../vendor/autoload.php';
use DoYouPhp\PhpDesignPattern\Memento\MyMemento\Data;
use DoYouPhp\PhpDesignPattern\Memento\MyMemento\DataCaretaker;
// DataCaretakerクラスのコンストラクタで、セッションが開始される
$caretaker = new DataCaretaker();
// セッションがあればセッション、なければData型インスタンスをセット
$data = isset($_SESSION['data']) ? $_SESSION['data'] : new Data();
// postメソッドでボタンが押されたか確認する
$mode = (isset($_POST['mode']) ? $_POST['mode'] : null);
// 押されたボタンにより処理を分岐する
switch ($mode) {
case 'add':
// コメントをData型インスタンスに登録する
$data->addComment((isset($_POST['comment']) ? $_POST['comment'] : ''));
break;
case 'save':
// コメントのスナップショットを取り、保存する
// addされたコメントをDataSnapshot型インスタンスにセットしている
// それを引数にして、DataCaretaker型インスタンスにセッションとしてスナップショットを保管する
$caretaker->setSnapshot($data->takeSnapshot());
echo 'データを保存しました!'.'<br>'."\n";
break;
case 'restore':
// 保存したスナップショットを取得しコメントを復元する
// スナップショットはセッションとして保管されている
$data->restoreSnapshot($caretaker->getSnapshot());
echo 'データを復元しました!'.'<br>'."\n";
break;
case 'clear':
// Data型インスタンスを初期化する
// この時点では、セッションはまだ生きている状態
$data = new Data();
}
// 登録したコメントを取得し、表示する
// add, save, clearは表示される内容がそれぞれ異なる
echo '今までのコメント'.'<br>'."\n";
if (is_object($data)) {
echo '<ul>';
foreach ($data->getComment() as $comment) {
echo '<li>'.$comment.'</li>';
}
echo '</ul>';
}
// 次のアクセスで使うデータをセッションに保存する
$_SESSION['data'] = $data;
?>
<!-- 入力フォーム -->
<form action="" method="post">
コメント:<input type="text" name="comment"><br>
<input type="submit" name="mode" value="add">
<input type="submit" name="mode" value="save">
<input type="submit" name="mode" value="restore">
<input type="submit" name="mode" value="clear">
</form>
Author And Source
この問題について(【PHPデザインパターン】17_Memento~スナップショットを取る), 我々は、より多くの情報をここで見つけました https://qiita.com/yukibe/items/eb1be644934f872444f1著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .