範例:仿真Git (備忘錄模式)

Pattern: 備忘錄模式

Class Diagram: 仿真Git


情境:讓我們利用備忘錄模式,實作一個仿真Git

  • 首先定義Commit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php

namespace App\MementoPattern\Git;

/**
* This is our Memento in memento pattern
*/
class Commit
{
/**
* This is our state.
*
* @var string
*/
private $code;

public function __construct(string $code)
{
$this->code = $code;
}

public function getCode(): string
{
return $this->code;
}
}

Commit屬於備忘錄類別 (Memento)
負責儲存原始類別 (Originator) 的狀態。

在這個範例中,code就是我們的狀態。


  • 接著定義Folder
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?php

namespace App\MementoPattern\Git;

use App\MementoPattern\Git\Commit;

/**
* This is our CareTaker in memento pattern
*/
class Folder
{
/**
* @var Commit[]
*/
private $commits = [];

/**
* @param Commit $commit
*/
public function saveCommit(Commit $commit)
{
$this->commits[] = $commit;
}

/**
* @param int $previous
* @return Commit
*/
public function getPreviousCommit(int $previous): Commit
{
$commitAmount = count($this->commits);
$index = $commitAmount - $previous;

$result = $this->commits[$index];
return $result;
}
}

Folder屬於管理類別 (Caretaker)
負責管理Commit的存儲。


  • 接著是我們的Git類別
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<?php

namespace App\MementoPattern\Git;

use App\MementoPattern\Git\Commit;
use App\MementoPattern\Git\Folder;

/**
* This is our Originator in memento pattern
*/
class Git
{
/**
* @var Folder
*/
protected $folder;

/**
* This is our state.
*
* @var string
*/
private $code;

/**
* @param Folder $folder
*/
public function __construct(Folder $folder)
{
$this->folder = $folder;
}

/**
* Getter
*
* @return string
*/
public function getUntrackedCode(): string
{
return $this->code;
}

/**
* Setter
*
* @var string
*/
public function writeCode(string $code)
{
$this->code = $code;
}

public function commit()
{
$commit = $this->createCommit();
$this->code = '';

$this->folder->saveCommit($commit);
}

private function createCommit(): Commit
{
return new Commit($this->code);
}

/**
* @param int $previous
* @return string
*/
public function reset(int $previous): string
{
return $this->code = $this->folder->getPreviousCommit($previous)->getCode();
}
}

Git屬於我們的原始類別 (Originator) ,具有code狀態。

getUntrackedCode()及writeCode()是我們code狀態的Getter/Setter。

透過commit()方法,生成Commit,保存了當下code的狀態,
並傳給Folder作為紀錄存檔。

透過reset()方法,我們可以載入先前存檔好的code狀態。


  • 最後讓我們看客戶端的程式碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php

namespace App\MementoPattern\Git;

use App\MementoPattern\Git\Folder;
use App\MementoPattern\Git\Git;

class Program
{
public function run()
{
$folder = new Folder();
$git = new Git($folder);

$git->writeCode('aaa');
dump($git->getUntrackedCode()); //aaa

$git->commit();
dump($git->getUntrackedCode()); //''

$git->writeCode('bbb');
$git->commit();

$git->reset(1);
dump($git->getUntrackedCode()); //aaa
}
}

[單一職責原則]
我們將原始類別備忘錄類別管理類別視為三種職責。

[開放封閉原則]
透過備忘錄類別與管理類別,
原始類別不需要實作恢復狀態的相關功能。

ʕ •ᴥ•ʔ:這個範例只是利用Git作為媒介,與真實Git行為不完全相同。