在大致規劃好目錄架構之後,就可以開始模擬使用情境,設計出一呼叫套件的方式,把這個專案作品的使用範例先寫出來。

你可能會想說:「哇勒,這瞎咪碗糕?什麼程式都還沒開始寫,直接跳到最後一步啦?」

且慢,先不要酸啊 ><|| 讓筆者先提個例子先。

生活經驗的例子

不知道讀者們有無參觀過預售屋的經驗?

在銷售展示中心旁,只見開始挖地基、架設鷹架的工地被清綠色的鐵皮圍籬圍起來。萬丈高樓連平地都還沒開始起,就開始賣起這未來的房子啦。只見展示中心的中央擺著漂亮樣品屋的模型。電視螢幕撥放著房子蓋好後會是什麼樣子的 3D 模擬圖。

這個時候營造廠才正要按著建築設計圖施作,就為了要達到最後和 3D 模擬圖一模一樣。

模擬使用情境

雖然程式設計和前段生活經驗的例子中的建築工程,在本質上有很大的差異。但把事先模擬的這種概念拿來用,就和蓋房子一樣,最後的結果和一開始的架構都有了,就只差中間的過程了。

在真正寫程式之前,把要如何使用這個套件的範例寫出來,而這個範例就是最終的範例。而我們要做的就是依規劃好的架構,開始進行程式設計,讓最後的這個範例真的可以用。

架構

基本架構在 Day 16 已經先行規劃好了。大概的架構如下。

.
├── src
│   └── SimpleCache
│       ├── Cache.php
│       ├── CacheProvider.php
│       ├── Driver
│       │   ├── File.php
│       │   ├── Myql.php
│       │   ├── Redis.php
│       │   └── Sqlite.php
│       └── Exception
│           ├── CacheArgumentException.php
│           └── CacheException.php
└── tests
    └── SimpleCache
        ├── CacheTest.php
        ├── ...
        └── ...

假設範例 A

範例:/day-17/example-1/Main.php

<?php

use Shieldon\SimpleCache\Cache;
use Shieldon\SimpleCache\Driver\Redis;

class Main
{
    public function example()
    {
        $cache = new Cache('redis');
        $cache->set('foo', 'bar', 3600);

        echo $cache->get('foo');
        // echo: bar
    }
}

Cache 類別的建構子參數直接塞一個字串 redis,然後再內部實例化 Redis
這樣似乎綁死了這個類別只能使用這個專案作品中已實作的 Driver。

No, No, No。很不 OK 捏。

假設範例 B

想到之前 Day 8 提到的依賴注入 設計模式。改寫成如下:

範例:/day-17/example-2/Main.php

<?php

use Shieldon\SimpleCache\Cache;
use Shieldon\SimpleCache\Driver\Redis;

class Main
{
    public function example()
    {
        $redis = new Redis('127.0.0.1', 6379);

        $cache = new Cache($redis);
        $cache->set('foo', 'bar', 3600);

        echo $cache->get('foo');
        // echo: bar
    }
}

先實例化 Redis,然後注入 Cache 類別的建構子參數,這樣會不會比較彈性?
這樣做的話,就算不是專案裡已經有的 Driver,也以使用別人已經實作 PSR-16 的 CacheInterface 的類別,直接注入使用囉!

假設範例 C

雖然依賴注入的點子很不錯,但就覺得那裡怪怪的?
參數需要順序排列,而不同的 Driver 例如 SQLite,只需要一個參數,也就是一個絕對路徑目錄的字串。
Redis 這個 Driver 如果要連到外部伺服器的 Redis 服務,需要帳號及密碼,那麼參數又更多了。

範例:/day-17/example-3/Main.php

<?php

use Shieldon\SimpleCache\Cache;
use Shieldon\SimpleCache\Driver\Redis;

class Main
{
    public function example()
    {
        $redis = new Redis([
            'host' => '127.0.0.1',
            'port' => 6379,
        ]);

        $cache = new Cache($redis);
        $cache->set('foo', 'bar', 3600);

        echo $cache->get('foo');
        // echo: bar
    }

    public function example2()
    {
        $sqlite = new Sqlite([
            'path' => '/home/app/writable',
        ]);

        $cache = new Cache($sqlite);
        $cache->set('foo2', 'bar2', 3600);

        echo $cache->get('foo2');
        // echo: bar2
    }
}

把 Driver 的建構子參數改成只接受一個陣列類型的參數吧。這樣使用者就可以只記得每個 Driver 只有一個參數,而參數的陣列欄位定義出明確的 key 值在文件中方便查閱。

總結

程式設計好玩的地方就是,同樣的功能其實可以有很多不同的寫法。筆者的寫法並不是絕對。以前也常發生自己覺得很不錯的寫法,在一年後被自己嫌棄而整個重寫 XD。

不過在創造一個全新的套件時,用模擬的範例,或許會發現基本架構需要修改來配合期待的範例結果,也說不定。用這樣倒推回去思考整個設計的架構,在設計上是非常有幫助的唷!

本篇原始碼可在此瀏覽。我們明天見囉。

最後修改日期: 2022-02-06

作者

留言

撰寫回覆或留言

發佈留言必須填寫的電子郵件地址不會公開。