iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

0
Software Development

你終究都要學設計模式的,那為什麼不一開始就學呢?系列 第 42

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

本文同步更新於blog

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

  • 首先定義Commit
<?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
<?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類別
<?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狀態。


  • 最後讓我們看客戶端的程式碼
<?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
    }
}

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

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

最後附上類別圖:
https://ithelp.ithome.com.tw/upload/images/20201117/20111630dzEFOvxPJE.png
(註:若不熟悉 UML 類別圖,可參考UML類別圖說明。)

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


上一篇
Day41. 備忘錄模式
下一篇
Day43. 蠅量模式
系列文
你終究都要學設計模式的,那為什麼不一開始就學呢?44

尚未有邦友留言

立即登入留言