首頁  >  文章  >  後端開發  >  一文了解PHP中的原型模式

一文了解PHP中的原型模式

青灯夜游
青灯夜游轉載
2021-07-07 19:22:582963瀏覽

在先前的文章《淺談PHP中的迭代器模式》中我們介紹了PHP中的迭代器模式,以下這篇文章帶大家了解PHP中的一文了解PHP中的原型模式。

一文了解PHP中的原型模式

一文了解PHP中的原型模式其實更形象化的來說應該叫做克隆模式。它主要的行為是對物件進行克隆,但是又把被克隆的物件稱之為最初的原型,於是,這個模式就這樣被命名了。說真的,從使用方式來看真的感覺叫做克隆模式比較貼切一些。

Gof類別圖及解釋

GoF定義:用原型實例指定建立物件的種類,並且透過拷貝這些原型建立新的對象

GoF類別圖:

一文了解PHP中的原型模式

程式碼實作:

abstract class Prototype
{
    public $v = 'clone' . PHP_EOL;

    public function __construct()
    {
        echo 'create' . PHP_EOL;
    }

    abstract public function __clone();
}

首先我們透過模擬的方式定義了一個原型,這裡主要是模擬了__clone()這個方法。其實這是PHP自備的魔術方法,根本是不需要我們去進行定義的,只需要在原型類別中進行實作就可以了。當外部使用clone關鍵字進行物件克隆時,直接就會進入這個魔術方法。在這個魔術方法裡面我們可以對屬性進行處理,特別是針對引用屬性進行一些獨特的處理。在這個例子中,我們只使用了一個值類型的變數。無法體現出引用類型的問題,我們將在後面的實例中示範對引用類型變數的處理。

class ConcretePrototype1 extends Prototype
{
    public function __clone()
    {
    }
}

class ConcretePrototype2 extends Prototype
{
    public function __clone()
    {
    }
}

模擬的具體實現的原型,其實就是主要去具體的實作__clone()方法。後面我們看具體的例子時再說明。

class Client
{
    public function operation()
    {
        $p1 = new ConcretePrototype1();
        $p2 = clone $p1;

        echo $p1->v;
        echo $p2->v;
    }
}

$c = new Client();
$c->operation();

客戶端使用clone來複製一文了解PHP中的原型模式p2也具有相同的$v屬性。

  • 一文了解PHP中的原型模式看似就是複製了一個相同的對象,但是請注意,複製的時候,__construct()方法並沒有被調用,也就是當你運行這段程式碼的時候,create只輸出了一次。這也帶出了一文了解PHP中的原型模式最大的一個特點-減少創建物件時的開銷
  • 基於上述特點,我們可以快速的複製大量相同的對象,例如要給一個數組中塞入大量相同的對象時。
  • 複製出來的物件中如果都是值類型的屬性,我們可以任意修改,不會對原型產生影響。而如果有引用類型的變量,則需要在__clone()方法進行一些處理,否則修改了複製物件的引用變數中的內容,會對原型物件中的內容有影響。

我們的手機作業系統(也可以想像PC電腦的作業系統),都是怎麼安裝到裝置中呢?其實都是不停的複製拷貝最初的那一套系統。用微軟的例子非常好說明這個問題,當年微軟能夠成為一個帝國,其實也是因為他不停的將winodws作業系統拷貝複製到光碟中,然後賣給千家萬戶(當然,這裡沒中國什麼事) 。而中國市場呢,大量的高手破解了windows之後也是由這份文件不停的複製拷貝才裝到了我們的電腦中。手機、智慧型裝置等各類產品的作業系統、軟體都是如此。一次開發無限拷貝正是軟體產業暴利的原因。畢竟我們的系統也是由不少的工程師日以繼夜的996在Android原生系統的基礎上開發出來的,趕緊不斷的複製到即將出廠的手機上吧! !

完整代码:https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2Fzhangyue0503%2Fdesignpatterns-php%2Fblob%2Fmaster%2F08.prototype%2Fsource%2Fprototype.php

實例

同樣還是拿手機來說事兒,這次我們是根據不同的運營商需要去開發一批定制機,也就是套餐機。這批手機說實話都沒有什麼不同,大部分都是相同的配置,但是運營商系統不同,而且偶爾有一些型號的CPU和內存也可能存在不同。這時候,我們就可以用一文了解PHP中的原型模式來進行快速的複製並且只修改一部分不相同的地方啦。

一文了解PHP中的原型模式生產手機類別圖:

一文了解PHP中的原型模式

#
完整源码:https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2Fzhangyue0503%2Fdesignpatterns-php%2Fblob%2Fmaster%2F08.prototype%2Fsource%2Fprototype-phone.php
<?php
interface ServiceProvicer
{
    public function getSystem();
}

class ChinaMobile implements ServiceProvicer
{
    public $system;
    public function getSystem(){
        return "中国移动" . $this->system;
    }
}
class ChinaUnicom implements ServiceProvicer
{
    public $system;
    public function getSystem(){
        return "中国联通" . $this->system;
    }
}

class Phone 
{
    public $service_province;
    public $cpu;
    public $rom;
}

class CMPhone extends Phone
{
    function __clone()
    {
        // $this->service_province = new ChinaMobile();
    }
}

class CUPhone extends Phone
{
    function __clone()
    {
        $this->service_province = new ChinaUnicom();
    }
}


$cmPhone = new CMPhone();
$cmPhone->cpu = "1.4G";
$cmPhone->rom = "64G";
$cmPhone->service_province = new ChinaMobile();
$cmPhone->service_province->system = &#39;TD-CDMA&#39;;
$cmPhone1 = clone $cmPhone;
$cmPhone1->service_province->system = &#39;TD-CDMA1&#39;;

var_dump($cmPhone);
var_dump($cmPhone1);
echo $cmPhone->service_province->getSystem();
echo $cmPhone1->service_province->getSystem();


$cuPhone = new CUPhone();
$cuPhone->cpu = "1.4G";
$cuPhone->rom = "64G";
$cuPhone->service_province = new ChinaUnicom();
$cuPhone->service_province->system = &#39;WCDMA&#39;;
$cuPhone1 = clone $cuPhone;
$cuPhone1->rom = "128G";
$cuPhone1->service_province->system = &#39;WCDMA1&#39;;

var_dump($cuPhone);
var_dump($cuPhone1);
echo $cuPhone->service_province->getSystem();
echo $cuPhone1->service_province->getSystem();

說明:

  • 一文了解PHP中的原型模式

    ############################################################ #####印了很多東西呀,不過主要的還是看看行動手機,也就是CMPhone中的__clone()方法,我們沒有重新去初始化一個新物件。這時,複製的###cmPhone中的是同一個物件。沒錯,這就是引用的複製問題。引用只是複製了引用的位址,他們指向的是同一個物件。當###

    cmPhone裡面的service_province物件裡面的屬性也跟著改變了。

  • 在CUPhone中,我們重新new了一個新的service_province物件。這次外面的

    cuPhone中引用物件的值。

  • 一文了解PHP中的原型模式中最主要的就是要注意上述兩點,而普通的值屬性會直接進行複製,不會產生這個問題。這裡又牽涉出另外兩個概念:淺複製深複製
  • #淺複製,是指被複製物件的所有變數都含有與原來物件相同的值,而所有的對其他對象的引用都仍然指向原來的對象
  • 深複製把引用對象的變數指向複製過的新對象,而不是原有的被引用的對象
  • 關於引用和值的問題,我們將在其他的文章中進行講解,請關注微信或掘金號

原文地址:https://juejin.cn/post/ 6844903942220939272

作者:硬核專案經理

推薦學習:《PHP影片教學

以上是一文了解PHP中的原型模式的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:juejin.cn。如有侵權,請聯絡admin@php.cn刪除