快轉到主要內容
Background Image

【PHP 設計模式】單例模式 Singleton Pattern

乾太 ₍₍ ◝(・◡・)◟ ⁾⁾
作者
乾太 ₍₍ ◝(・◡・)◟ ⁾⁾
一起寫程式的好朋友。
目錄
單例模式,整個應用程式只會有一個實體,這個實體不會重複建立,就有點像是整座島上只有一個曹賣,這個曹賣在你這座島的時間,你可以盡量找他買大頭菜,無論你做什麼事情,大頭菜在這段時間內都不會任意更動,你的曹賣是你的曹賣,不會因為你進去博物館逛一圈再出來而改變。

什麼是單例模式
#

單例模式核心概念

單例模式確保一個類別只有一個實例,並提供全域的存取點。這在管理共享資源或配置時非常有用。

UML
#

Singleton Pattern UML 類別圖
Singleton Pattern 設計模式的 UML 類別關係圖

實作
#

建立大頭菜類別
#

實作步驟

我們需要建立一個大頭菜類別,裡面放著一顆大頭菜。

Turnips.php
#

/**
 * Class Turnips.
 */
final class Turnips
{
    /**
     * @var Turnips
     */
    protected static $turnips;
}

實作獲取方法
#

再來我們需要有個方法來獲得這顆大頭菜,並且這顆大頭菜只要被建立過,無論怎麼建立大頭菜,所獲得的物件永遠會是第一顆大頭菜。

Turnips.php
#

    /**
     * 透過延遲載入的方式來取得大頭菜
     * 
     * @return Turnips
     */
    public static function getTurnips(): Turnips
    {
        if (static::$turnips === null) {
            static::$turnips = new static();
        }

        return static::$turnips;
    }

防止例外狀況
#

重要措施

最後為了防止大頭菜被用各種意想不到的 BUG 來建立,所以要設下種種防線。

Turnips.php
#

    /**
     * 不允許自己生產大頭菜,你必須去跟曹賣買
     * 為了防止玩家自己生產大頭菜,必須透過 Turnips::getTurnips() 方法來取得大頭菜
     */
    private function __construct()
    {
        // ...
    }

    /**
     * 防止大頭菜被玩家複製
     */
    private function __clone()
    {
        // ...
    }

    /**
     * 防止大頭菜被反序列化,這個過程會建立大頭菜的副本
     */
    private function __wakeup()
    {
        // ...
    }

測試
#

測試項目
#

最後為了驗證我們前面所撰寫的大頭菜是否正確,我們需要寫個測試,測試建立兩個大頭菜,並且獲取大頭菜物件,比對一下兩個是不是都是大頭菜,以及兩個是不是一樣的大頭菜。

測試程式碼
#

SingletonPatternTest.php
#

use PHPUnit\Framework\TestCase;

/**
 * Class SingletonPatternTest.
 */
class SingletonPatternTest extends TestCase
{
    /**
     * 建立兩個大頭菜,比較兩個是否都是大頭菜,而且兩個大頭菜都是一模一樣的東西。
     * 
     * @test
     */
    public function test_uniqueness()
    {
        $turnipsA = Turnips::getTurnips();
        $turnipsB = Turnips::getTurnips();

        $this->assertInstanceOf(Turnips::class, $turnipsA);
        $this->assertInstanceOf(Turnips::class, $turnipsB);
        $this->assertSame($turnipsA, $turnipsB);
    }
}

測試結果
#

最後測試的執行結果會獲得如下:

PHPUnit Pretty Result Printer 0.28.0 by Codedungeon and contributors.
==> Configuration: ~/php-design-pattern/vendor/codedungeon/phpunit-result-printer/src/phpunit-printer.yml

PHPUnit 9.2.6 by Sebastian Bergmann and contributors.

 ==> AbstractFactoryTest        ✔  ✔  ✔  ✔  
 ==> BuilderPatternTest         ✔  ✔  
 ==> FactoryMethodTest          ✔  ✔  ✔  ✔  
 ==> PoolPatternTest            ✔  ✔  
 ==> PrototypePatternTest       ✔  ✔  
 ==> SimpleFactoryTest          ✔  ✔  ✔  ✔  
 ==> SingletonPatternTest       ✔  
 ==> StaticFactoryTest          ✔  ✔  ✔  ✔  ✔  

Time: 00:00.050, Memory: 6.00 MB

OK (24 tests, 68 assertions)

完整程式碼
#

設計模式不難,找回快樂而已,以大頭菜為例。

參考文獻
#

相關文章

淺入淺出 PHP 閉包 Closure
深入了解 PHP 閉包 (Closure) 的核心概念、使用方式與實務應用。從基本語法到進階技巧,全面掌握 PHP 匿名函數的強大功能。
如何將你的 Laravel boilerplate 專案成功部署到 HeroKu
·266 字·2 分鐘
事情是這樣的,最近在研究 HeroKu 這家雲端平台,想要嘗試將一些服務部署到 HeroKu 上頭,但卻遇到一些問題,因此將一系列的問題解決過程記錄下來
如何在 Swift 當中透過 String Format 格式來簡單處理數值內容?
·266 字·2 分鐘
在開發應用程式時,我們經常會需要做數值轉換成特定格式,例如將小數點數值取兩位就好,或者整數補 0 到十位數,諸如此類的功能,接下來我們就直接進入實際應用