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行为不完全相同。


<<:  JS 原型(prototype) DAY66

>>:  Dashboard制作教学:做一张互动式仪表板,只需要5步!超简单~

Day05 媒体协商与SDP

媒体协商 上一篇提到,要进行 WebRTC的连线需要处理以下两个问题,今天我们就来看看媒体协商的部分...

Rust-流程控制-for

如果想印出1到100的数字,更常的做法是使用for回圈而不是while 例 for i in 1.....

Day 10 开始你的广告活动吧

当我们熟建立了关键字的基本概念後,那不妨开始在 Google Ads 建立完善的广告活动吧,并透过一...

Day18 Combine 05 - Operators 类型介绍 : 转换操作符

转换操作符 map/mapError map操作符会执行给定的闭包,将上游发布的内容进行转换,然後再...

Day29:歪楼无极限(全英文笔记 - III)

虽然今天已经是最後一天,但如果明天系统仍然可以发文的话,会先继续发文,方便之後回顾整理系列文时,能够...