PHP 簡單的幾個設計模式(個人理解)

zgxxx發表於2018-11-08

我的github部落格 https://zgxxx.github.io/

設計模式六大原則

開放封閉原則:一個軟體實體如類、模組和函式應該對擴充套件開放,對修改關閉。
里氏替換原則:所有引用基類的地方必須能透明地使用其子類的物件.
依賴倒置原則:高層模組不應該依賴低層模組,二者都應該依賴其抽象;抽象不應該依賴細節;細節應該依賴抽象。
單一職責原則:不要存在多於一個導致類變更的原因。通俗的說,即一個類只負責一項職責。
介面隔離原則:客戶端不應該依賴它不需要的介面;一個類對另一個類的依賴應該建立在最小的介面上。
迪米特法則 :一個物件應該對其他物件保持最少的瞭解。

單例模式 (建立設計模式)

要點:只有一個例項,作為物件的建立模式,單例模式確保某一個類只有一個例項,而且自行例項化並向整個系統提供這個例項。
常見: 資料庫連線,日誌錯誤記錄(多種用途使用多種模式)

<?php

/**
 * 單例模式
 */
class Singleton
{
    /**
     * @var self[儲存例項]
     */
    private static $instance;

    /**
     * @var
     */
    public $mix;

    /**
     * return self instance [建立一個用來例項化物件的方法]
     */
    public static function getInstace()
    {
        var_dump(isset(self::$instance));
        if (!self::$instance instanceof self) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * Singleton constructor.建構函式為private,防止建立物件
     */
    private function __construct()
    {
        echo "例項初始化了";
    }

    private function __clone()
    {
        // TODO: Implement __clone() method.
        trigger_error('Clone is not allowed!');
    }
}

// @Test
$firstSingle = Singleton::getInstace();
$secondSingle = Singleton::getInstace();

$firstSingle->mix = 'one';
//一開始mix是賦值‘one',所以列印出one
print_r($firstSingle->mix);

//由於getInstace該方法保證了Singleton類只能有一個例項,不會再重新new,minx依然用firstSingle的,mix被改變成’two‘
$secondSingle->mix = 'two';  
print_r($firstSingle->mix);
print_r($secondSingle->mix);

列印結果:bool(false) 例項初始化了bool(true) onetwotwo

簡單工廠模式 (建立設計模式)

要點:可以根據引數的不同返回不同類的例項。簡單工廠模式專門定義一個類來負責建立其他類的例項,被建立的例項通常都具有共同的父類。

<?php

/**
 * 簡單工廠模式
 */

interface SystemFactory
{
    public function createSystem($type);
}

class MySystemFactory implements SystemFactory
{
    // 實現工廠方法
    public function createSystem($type)
    {
        switch ($type) {
            case 'Mac':
                return new MacSystem();
            case 'Win':
                return new WinSystem();
            case 'Linux':
                return new LinuxSystem();
        }
    }
}

class MacSystem
{
    public function __construct()
    {
        echo "I am Mac system</br>";
    }
}

class WinSystem
{
    public function __construct()
    {
        echo "I am Win system</br>";
    }
}

class LinuxSystem
{
    public function __construct()
    {
        echo "I am Linux system</br>";
    }
}

//建立系統工廠
$systemObj = new MySystemFactory();

$systemArray = array('Mac','Linux','Win');
foreach ($systemArray as $val) {
    $systemObj->createSystem($val);
}

列印結果:
I am Mac system
I am Linux system
I am Win system

工廠模式 (建立設計模式)

要點:此模式中,透過定義一個抽象的核心工廠類,並定義建立產品物件的介面,建立具體產品例項的工作延遲到其工廠子類去完成。這樣做的好處是核心類只關注工廠類的介面定義,而具體的產品例項交給具體的工廠子類去建立。當系統需要新增一個產品,無需修改現有系統程式碼,只需要新增一個具體產品類和其對應的工廠子類,是系統的擴充套件性變得很好,符合物件導向程式設計的開閉原則;

我的理解:

按我平時喜歡玩的籃球遊戲nba2k系列來代入。我來模擬整個NBA聯盟,一開始是沒有球員的,我需要不斷的建立球員,具體就交給Nba底下的各個子類,也就是各個球隊去建立就好

首先有一個球員介面,可以定義球員的投射還有搶籃板球的動作,注意這裡的每個球員暫時只有這兩個動作,生產出來的球員只有投射和搶籃板動作

interface Player{
    public function shot();
    public function rebound();
}

然後具體到球員自己的動作

class Wade implements Player
{
    public function shot()
    {
        echo "I can shot in middle distance<br>";
    }
    public function rebound()
    {
        echo "I can crash the boards <br>";
    }
}

class Kobe implements Player
{
    public function shot()
    {
        echo "I can shot the three-point <br>";
    }
    public function rebound()
    {
        echo "I can crash the boards <br>";
    }
}

定義一個抽象的核心工廠類,也就是整個遊戲有一個建立球員頁面

abstract class NbaFactory{
    abstract  static function createPlayer();
}

我喜歡熱火,就來操作熱火還有湖人好了,創一個韋德還有科比來玩玩

class HeatTeam extends NbaFactory{
    public static function createPlayer()
    {
        return new Wade();
    }
}
class LakersTeam extends  NbaFactory{
    public static function createPlayer()
    {
        return new Kobe();
    }
}

一切準備好了,就去場上試試能不能打:選人然後投籃搶籃板

$heatPlayer = HeatTeam::createPlayer();
$heatPlayer->shot();
$heatPlayer->rebound();

$lakersPlayer = LakersTeam::createPlayer();
$lakersPlayer->shot();
$lakersPlayer->rebound();

所以工廠模式:不需要NBA這個背後大boss親自去建立球員,只需要定義一個想要建立球員這樣的介面,例項工作就交給子類也就是球隊去建立就行了,當我們想要增加一個自己喜歡的球員來玩,只需要新增一個具體的球員,然後設定他有什麼動作呀,能力呀,再對應你想要他在哪一支隊伍就ok了,這樣就不需要修改現有系統程式碼,系統的擴充套件性變得很好,符合物件導向程式設計的開閉原則

整體程式碼如下:

<?php

/**
 *  球員動作
 * Interface Player
 */
interface Player{
    public function shot();
    public function rebound();
}

/**
 * 設定韋德投籃以及搶籃板
 * Class Wade
 */
class Wade implements Player
{
    public function shot()
    {
        echo "I can shot in middle distance<br>";
    }
    public function rebound()
    {
        echo "I can crash the boards <br>";
    }
}

/**
 * 設定科比投籃以及搶籃板
 * Class Kobe
 */
class Kobe implements Player
{
    public function shot()
    {
        echo "I can shot the three-point <br>";
    }
    public function rebound()
    {
        echo "I can crash the boards <br>";
    }
}

/**
 * 整個遊戲NBA具備建立球員這一項功能
 * Class NbaFactory
 */
abstract class NbaFactory{
    abstract  static function createPlayer();
}

/**
 * 熱火隊建立了韋德這樣的球員
 * Class HeatTeam
 */
class HeatTeam extends NbaFactory{
    public static function createPlayer()
    {
        return new Wade();
    }
}

/**
 * 湖人隊建立了科比這樣的球員
 * Class LakersTeam
 */
class LakersTeam extends  NbaFactory{
    public static function createPlayer()
    {
        return new Kobe();
    }
}

/**
 *  選擇熱火隊,並且測試韋德的動作
 */
$heatPlayer = HeatTeam::createPlayer();
$heatPlayer->shot();
$heatPlayer->rebound();

/**
 *  選擇湖人隊,並且測試科比的動作
 */
$lakersPlayer = LakersTeam::createPlayer();
$lakersPlayer->shot();
$lakersPlayer->rebound();

抽象工廠模式 (建立設計模式)

要點:提供一個建立一系列相關或相互依賴物件的介面。注意:這裡和工廠方法的區別是:一系列(多個),而工廠方法只有一個。。在工廠方法模式中,一個具體的工廠負責生產一類具體的產品,即一對一的關係,但是,如果需要一個具體的工廠生產多種產品物件,那麼就需要用到抽象工廠模式了。

我的理解:
工廠模式,一個工廠輔助生產一類具體的產品,就像上邊的例子,球員建立,只有投籃還有搶籃板動作,無論建立韋德科比還是詹姆斯都是隻有這兩種。而抽象工廠,需要生產多種產品,例如下面有兩個遊戲頁面,球衣樣式設定和球鞋樣式設定,這兩個頁面底下是各種包含自己的方法,球衣頁面是主客場球衣設定,球鞋頁面是高低幫和顏色設定。

整體程式碼如下:

<?php

/**
 * 球衣樣式設定(客場球衣&主場球衣)
 * Interface Uniform
 */
interface Uniform{
    public function home();
    public function away();
}

/**
 * 設定熱火主客場球衣樣式
 * Class HeatUniform
 */
class HeatUniform implements Uniform
{
    public function home()
    {
        echo "Set the Heat's uniform with red and white <br>";
    }

    public function away()
    {
        echo "Set the Heat's uniform with black and red <br><br>";
    }
}

/**
 *  球鞋樣式設定(球鞋款式&球鞋主顏色)
 * Interface Shoes
 */
interface Shoes{
    public function style();
    public function color();
}

/**
 * 設定熱火主客場球衣樣式
 * Class HeatUniform
 */
class HeatShoes implements Shoes
{
    public function style()
    {
        echo "Set the Heat's Shoes'style as height shoes <br>";
    }
    public function color()
    {
        echo "Set the Heat's Shoes'color as white <br>";
    }
}

/**
 * 遊戲球隊設定頁面,包括了服裝設定和球鞋設定
 * Class TeamSetting
 */
abstract class TeamSetting{
    abstract public static function setUniform();
    abstract public static function setShoes();
}

/**
 * 熱火隊的球隊設定頁面,有熱火球衣和熱火球鞋設定
 * Class HeatSetting
 */
class HeatSetting extends TeamSetting
{
    public static function setUniform()
    {
        return new HeatUniform();
    }
    public static function setShoes()
    {
        return new HeatShoes();
    }
}

/**
 * 操作一:進入熱火隊球衣設定,主場球衣設定為紅白,客場球衣設定為紅黑
 */
$myControl1 = HeatSetting::setUniform();
$myControl1->home();
$myControl1->away();
/**
 * 操作二:進入熱火隊球鞋設定,球鞋樣式設定為高幫,顏色設定為白色
 */
$myControl2 = HeatSetting::setShoes();
$myControl2->style();
$myControl2->color();
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章