溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

PHP設(shè)計(jì)模式之原型模式的示例分析

發(fā)布時(shí)間:2021-06-11 15:39:09 來(lái)源:億速云 閱讀:174 作者:小新 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要介紹PHP設(shè)計(jì)模式之原型模式的示例分析,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

本文實(shí)例講述了PHP設(shè)計(jì)模式之原型模式定義與用法。分享給大家供大家參考,具體如下:

原型設(shè)計(jì)模式(Prototype Design Pattern)很有意思, 因?yàn)樗褂昧艘环N克隆技術(shù)來(lái)復(fù)制實(shí)例化的對(duì)象. 新對(duì)象是通過(guò)復(fù)制原型實(shí)例來(lái)創(chuàng)建的. 在這里, 實(shí)例是批實(shí)例化的具體類(lèi).原型設(shè)計(jì)模式的目的是通過(guò)使用克隆來(lái)減少實(shí)例化對(duì)象的開(kāi)銷(xiāo).與其從一個(gè)類(lèi)實(shí)例化新對(duì)象, 完全可以使用一個(gè)已有實(shí)例的克隆.

克隆函數(shù)

PHP中使用原型設(shè)計(jì)模式的關(guān)鍵是要了解如何使用內(nèi)置函數(shù)__clone().

<?php
abstract class CloneObject
{
  public $name;
  public $picture;
  abstract function __clone();
}
class Boy extends CloneObject
{
  public function __construct()
  {
    $this->face = "handsome";
    $this->name = "chenqionghe";
  }
  public function display()
  {
    echo 'look : '.$this->face;;
    echo '<br />'.$this->name.'<br />';
  }
  public function __clone() {}
}
$boy = new Boy();
$boy->display();
$cloneBoy = clone $boy;
$cloneBoy->face = "still handsome";
$cloneBoy->display();

運(yùn)行結(jié)果如下

look : handsome
chenqionghe
look : still handsome
chenqionghe

$cloneBoy實(shí)例是通過(guò)克隆Boy的實(shí)例$boy, 它可以像$boy一樣訪(fǎng)問(wèn)相同的屬性, 而且像Boy類(lèi)的直接實(shí)例一樣改變這些屬性.

注意: 對(duì)于所克隆的實(shí)例 , clone關(guān)鍵字會(huì)為該實(shí)例的類(lèi)實(shí)例化另一個(gè)實(shí)例(使用克隆關(guān)鍵字可以創(chuàng)建一個(gè)類(lèi)的副本, 如果可能, 會(huì)自動(dòng)調(diào)用對(duì)象的__clone方法, 但不能直接調(diào)用 對(duì)象的__clone方法), 關(guān)于過(guò)程, 有一點(diǎn)需要注意的是, 克隆不會(huì)不會(huì)啟動(dòng)構(gòu)造函數(shù)中的動(dòng)作.

簡(jiǎn)單的原型例子

我們以研究果蠅為例.研究的目標(biāo)是建立一個(gè)原型果蠅, 然后一旦出現(xiàn)變異, 就構(gòu)建這個(gè)變異果蠅

抽象類(lèi)接口和具體實(shí)現(xiàn)

原型(IPrototype)的兩個(gè)具體類(lèi)實(shí)現(xiàn)分別表示不同性別的果蠅, 包括性別變量(gender)和不同性別的和行為.

IPrototype.php

<?php
abstract class IPrototype
{
  public $eyeColor;
  public $winBeat;
  public $unitEypes;
  abstract function __clone();
}

IPrototype的這兩個(gè)實(shí)現(xiàn)的區(qū)別體現(xiàn)在性別上, 性別用常量標(biāo)識(shí), 一個(gè)是MALE,另一個(gè)是FEMAIL.雄果蠅有一個(gè)$mated布爾變量, 雄果蠅交配后,這個(gè)布爾變量會(huì)設(shè)置為true, 雌果蠅有一個(gè)$fecundity變量,其中包含一個(gè)數(shù)字值, 表示這只雄果蠅的繁殖能力(產(chǎn)卵個(gè)數(shù)):

MaleProto.php

<?php
include_once('IPrototype.php');
class MaleProto extends IPrototype
{
  const gender = "MALE";
  public $mated;
  public function __construct()
  {
    $this->eyeColor = "red";
    $this->winBeat = "220";
    $this->unitEypes = "760";
  }
  public function __clone(){}
}

FemaleProto.php

<?php
include_once('IPrototype.php');
class FemaleProto extends IPrototype
{
  const gender = "FEMAIL";
  public $fecundity;
  public function __construct()
  {
    $this->eyeColor = "red";
    $this->winBeat = "220";
    $this->unitEypes = "760";
  }
  public function __clone(){}
}

客戶(hù)

在原型設(shè)計(jì)模式中,Clien類(lèi)確實(shí)是一個(gè)不可缺少的部分.原因在于, 盡管要將子類(lèi)具體實(shí)現(xiàn)作為實(shí)例的模板,但使用相同的模板克隆實(shí)例的具體工作是由Client類(lèi)完成的

Client.php

<?php
function __autoload($class_name)
{
  include_once $class_name.'.php';
}
class Client
{
  //用于直接實(shí)例化
  private $fly1;
  private $fly2;
  //用于克隆
  private $c1Fly;
  private $c2Fly;
  private $updatedCloneFly;
  public function __construct()
  {
    //實(shí)例化
    $this->fly1 = new MaleProto();
    $this->fly2 = new FemaleProto();
    //克隆
    $this->c1Fly = clone $this->fly1;
    $this->c2Fly = clone $this->fly2;
    $this->updatedCloneFly = clone $this->fly2;
    //更新克隆
    $this->c1Fly->mated = "true";
    $this->c2Fly->fecundity = '186';
    $this->updatedCloneFly->eyeColor = "purple";
    $this->updatedCloneFly->winBeat = "220";
    $this->updatedCloneFly->unitEyes = '750';
    $this->updatedCloneFly->fecundity = '92';
    //通過(guò)類(lèi)型提示方法發(fā)送
    $this->showFly($this->c1Fly);
    $this->showFly($this->c2Fly);
    $this->showFly($this->updatedCloneFly);
  }
  private function showFly(IPrototype $fly)
  {
    echo "Eye color: ".$fly->eyeColor."<br />";
    echo "Wing Beats/second: ".$fly->winBeat."<br />";
    echo "Eye units: ".$fly->unitEypes."<br />";
    $genderNow = $fly::gender;
    echo "Gender: ".$genderNow."<br />";
    if($genderNow == "FEMAIL")
    {
      echo "Number of eggs: ".$fly->fecundity."<hr />";
    }
    else
    {
      echo "Mated: ".$fly->mated."<hr />";
    }
  }
}
$worker = new Client();

運(yùn)行結(jié)果如下

Eye color: red
Wing Beats/second: 220
Eye units: 760
Gender: MALE
Mated: trueEye color: red
Wing Beats/second: 220
Eye units: 760
Gender: FEMAIL
Number of eggs: 186Eye color: purple
Wing Beats/second: 220
Eye units: 760
Gender: FEMAIL
Number of eggs: 92

原型模式要依賴(lài)客戶(hù)通過(guò) 不念克隆過(guò)程使用具體原型.在這個(gè)設(shè)計(jì)過(guò)程中, 客戶(hù)是完成克隆的參與者, 由于克隆是原型設(shè)計(jì)中的關(guān)鍵要素, 所以客戶(hù)是一個(gè)基本參與者, 而不僅僅是一個(gè)請(qǐng)求類(lèi).

現(xiàn)代企業(yè)組織

在創(chuàng)建型設(shè)計(jì)模式方面,現(xiàn)代企業(yè)組織就非常適合原型實(shí)現(xiàn).現(xiàn)在企業(yè)組織往往是復(fù)雜而龐大的層次結(jié)構(gòu), 像面向?qū)ο缶幊桃粯?要為很多共同的特征建模.現(xiàn)在通過(guò)一個(gè)例子描述軟件工程公司.

軟件工程公司是一個(gè)典型的現(xiàn)代組織.工程部(Engineering Department)負(fù)責(zé)創(chuàng)建產(chǎn)品,管理部(Management)處理資源的協(xié)調(diào)組織,市場(chǎng)部(Marketing)負(fù)責(zé)產(chǎn)品的銷(xiāo)售,推廣和整體營(yíng)銷(xiāo).

接口中的封裝

在這個(gè)原型實(shí)現(xiàn)中,首先為程序的接口(一個(gè)抽象類(lèi))增加OOP,與所有原型接口一樣,這個(gè)接口包含一個(gè)克隆操作.另外它還包含一些抽象和具體的獲取方法和設(shè)置方法.其中有一個(gè)抽象獲取方法/設(shè)置方法對(duì),但要由3個(gè)具體原型實(shí)現(xiàn)為這個(gè)抽象獲取方法/設(shè)置方法對(duì)提供具體實(shí)現(xiàn).其他獲取方法和設(shè)置方法分分別應(yīng)用于員工名,ID碼和照片等屬性.注意所有這些屬性都是保護(hù)屬性(protected),所以盡管具體的獲取方法和設(shè)置方法有公共可見(jiàn)性,但由于操作中使用的屬性具有保護(hù)和可見(jiàn)性,這就提供了某種程度的封裝:

<?php
abstract class IAcmePrototype
{
  protected $name;
  protected $id;
  protected $employeePic;
  protected $department;
  //部門(mén)
  abstract function setDept($orgCode);
  abstract function getDept();
  //名字
  public function setName($emName)
  {
    $this->name = $emName;
  }
  public function getName()
  {
    return $this->name;
  }
  //ID
  public function setId($emId)
  {
    $this->id = $emId;
  }
  public function getId()
  {
    return $this->id;
  }
  //雇員圖像
  public function setPic($ePic)
  {
    $this->employeePic = $ePic;
  }
  public function getPic()
  {
    return $this->employeePic;
  }
  abstract function __clone();
}

利用這些獲取方法和設(shè)置方法, 所有屬性的值都通過(guò)繼承的保護(hù)變量來(lái)設(shè)置.采用這種設(shè)計(jì), 擴(kuò)展類(lèi)及其實(shí)例可以得到更好的封裝.

接口實(shí)現(xiàn)

3個(gè)IAcmePrototype子類(lèi)都必須實(shí)現(xiàn)"dept"抽象方法以及__clone()方法.類(lèi)似地, 每個(gè)具體原型類(lèi)還包含一個(gè)常量UNIT,它提供一個(gè)賦值,可以由實(shí)例(包括克隆的對(duì)象)作為標(biāo)識(shí)

首先來(lái)看市場(chǎng)部的Marketing類(lèi):

Marketing.php

<?php
include_once('IAcmePrototype.php');
class Marketing extends IAcmePrototype
{
  const UNIT = "Marketing";
  private $sales = "sales";
  private $promotion = "promotion";
  private $strategic = "strategic planning";
  public function setDept($orgCode)
  {
    switch($orgCode)
    {
      case 101:
        $this->department = $this->sales;
        break;
      case 102:
        $this->department = $this->promotion;
        break;
      case 103:
        $this->department = $this->strategic;
        break;
      default :
        $this->department = "未識(shí)別的市場(chǎng)部";
    }
  }
  public function getDept()
  {
    return $this->department;
  }
  public function __clone() {}
}

setDept()方法的實(shí)現(xiàn)使用了一個(gè)參數(shù).并不是直接輸入市場(chǎng)部的部門(mén),這個(gè)方法的參數(shù)是一個(gè)數(shù)字碼, 通過(guò)一個(gè)switch語(yǔ)句,限制了3種可接受的情況和默認(rèn)情況,別外兩個(gè)原型實(shí)現(xiàn)也類(lèi)似

Management.php

<?php
include_once('IAcmePrototype.php');
class Management extends IAcmePrototype
{
  const UNIT = "Management";
  private $research = "research";
  private $plan = "planning";
  private $operations = "operations";
  public function setDept($orgCode)
  {
    switch($orgCode)
    {
      case 201:
        $this->department = $this->research;
        break;
      case 202:
        $this->department = $this->plan;
        break;
      case 203:
        $this->department = $this->operations;
        break;
      default :
        $this->department = "未識(shí)別的管理部";
    }
  }
  public function getDept()
  {
    return $this->department;
  }
  public function __clone() {}
}

Engineering.php

<?php
include_once('IAcmePrototype.php');
class Engineering extends IAcmePrototype
{
  const UNIT = "Engineering";
  private $development = "development";
  private $design = "design";
  private $sysAd = "system administration";
  public function setDept($orgCode)
  {
    switch($orgCode)
    {
      case 301:
        $this->department = $this->development;
        break;
      case 302:
        $this->department = $this->design;
        break;
      case 303:
        $this->department = $this->sysAd;
        break;
      default :
        $this->department = "未識(shí)別的工程部";
    }
  }
  public function getDept()
  {
    return $this->department;
  }
  public function __clone() {}
}

以上這3個(gè)具體原型實(shí)現(xiàn)分別有其特定用途,不過(guò)它們都符合接口,可以創(chuàng)建各個(gè)原型實(shí)現(xiàn)的一個(gè)實(shí)例, 然后根據(jù)需要克隆多個(gè)實(shí)例.這個(gè)克隆的工作由Client類(lèi)完成

客戶(hù)

客戶(hù)的設(shè)置非常簡(jiǎn)單: 分別創(chuàng)建各個(gè)具體原型的一個(gè)實(shí)例, 然后按以下列表來(lái)克隆各個(gè)實(shí)例:

市場(chǎng)部門(mén)實(shí)例:
-----市場(chǎng)部門(mén)克隆
-----市場(chǎng)部門(mén)克隆
管理部門(mén)實(shí)例
-----管理部門(mén)克隆
工程部門(mén)實(shí)例
-----工程部門(mén)克隆
-----工程部門(mén)克隆

將來(lái)只使用這些克隆對(duì)象.使用獲取方法和設(shè)置方法將各個(gè)特定情況的信息賦給這些克隆對(duì)象.以下是Client的實(shí)現(xiàn)

Client.php

<?php
function __autoload($class_name)
{
  include_once $class_name.'.php';
}
class Client
{
  private $market;
  private $manage;
  private $engineer;
  public function __construct()
  {
    $this->makeConProto();
    $Tess = clone $this->market;
    $this->setEmployee($Tess, "Tess Smith" , 101, 'ts101-1234', 'tess.png');
    $this->showEmployee($Tess);
    $Jacob = clone $this->market;
    $this->setEmployee($Jacob, "Jacob Jones" , 101, 'jj101-2234', 'jacob.png');
    $this->showEmployee($Jacob);
    $Ricky = clone $this->manage;
    $this->setEmployee($Ricky, "Ricky Rodriguez" , 203, 'rr101-5634', 'ricky.png');
    $this->showEmployee($Ricky);
    $Olivaia = clone $this->engineer;
    $this->setEmployee($Olivaia, "Olivaia Perez" , 302, 'op301-1278', 'olivia.png');
    $this->showEmployee($Olivaia);
    $John = clone $this->engineer;
    $this->setEmployee($John, "John Jacson" , 101, 'jj301-14548', 'john.png');
    $this->showEmployee($John);
  }
  private function makeConProto()
  {
    $this->market = new Marketing();
    $this->manage = new Management();
    $this->engineer = new Engineering();
  }
  private function showEmployee(IAcmePrototype $employeeNow)
  {
    $px = $employeeNow->getPic();
    echo "<img src=$px width='150' height='150' /><br />";
    echo $employeeNow->getName().'<br />';
    echo $employeeNow->getDept().':'.$employeeNow::UNIT.'<br />';
    echo $employeeNow->getId().'<hr />';
  }
  private function setEmployee(IAcmePrototype $employeeNow, $nm, $dp, $id, $px)
  {
    $employeeNow->setName($nm);
    $employeeNow->setDept($dp);
    $employeeNow->setId($id);
    $employeeNow->setPic($px);
  }
}
$worker = new Client();

解釋:

客戶(hù)Client的構(gòu)造函數(shù)類(lèi)包含3個(gè)私有屬性, 用來(lái)分別實(shí)例化3個(gè)具體原型類(lèi). makeConPro()方法生成必要的實(shí)例.

接下來(lái),使用克隆技術(shù)創(chuàng)建一個(gè)"員工"實(shí)例.然后,這個(gè)實(shí)例向一個(gè)設(shè)置方法setEmployee()發(fā)送特定的實(shí)例信息,這個(gè)設(shè)置方法使用IAcmePrototype接口類(lèi)型提示,不過(guò)需要說(shuō)明, 它只對(duì)第一個(gè)參數(shù)使用類(lèi)型提示,其他參數(shù)都沒(méi)有類(lèi)型提示, 并不要求它們派生自IAcmePrototype接口.克隆"員工"可以使用IAcmePrototype抽象類(lèi)的所有設(shè)置方法以及具體原型類(lèi)實(shí)現(xiàn)的setDept()方法.

要使用各個(gè)員工的數(shù)據(jù),Client類(lèi)可以使用繼承的獲取方法.以下是運(yùn)行Client輸出的結(jié)果

Tess Smith
sales:Marketing
ts101-1234
Jacob Jones
sales:Marketing
jj101-2234
Ricky Rodriguez
operations:Management
rr101-5634
Olivaia Perez
design:Engineering
op301-1278
John Jacson
未識(shí)別的工程部:Engineering
jj301-14548

可以根據(jù)需要增加更多的克隆, 而且只需要對(duì)具體原型類(lèi)完成一次實(shí)例化.使用原型模式時(shí), 并不是建立具體類(lèi)的多個(gè)實(shí)例,而只需要一個(gè)類(lèi)實(shí)例化和多個(gè)克隆.

完成修改,增加特性

要記住,最重要(可能也是最基本)的是, 設(shè)計(jì)模式允許開(kāi)發(fā)人員修改和增補(bǔ)程序,而不必一切從頭開(kāi)始.例如, 假設(shè)總裁決定公司增加一個(gè)新的部門(mén),比如研究部門(mén)(Research), 這會(huì)很難嗎?一點(diǎn)也不難.Research可以擴(kuò)展IAcmePrototype抽象類(lèi), 然后實(shí)現(xiàn)抽象獲取方法和設(shè)置方法來(lái)反映這個(gè)研究部門(mén)的組織.需要說(shuō)明,Client類(lèi)中獲取方法和設(shè)置方法使用的代碼提示指示一個(gè)接口,而不是一個(gè)抽象類(lèi)的具體實(shí)現(xiàn).所以, 只要增加的單元正確地實(shí)現(xiàn)了這個(gè)接口,就能順利地增加到應(yīng)用中, 而不會(huì)帶來(lái)波動(dòng),也不需要對(duì)程序中的其他參與者進(jìn)行重構(gòu).

不僅可以增加更多的具體類(lèi), 還可以很容易地對(duì)各個(gè)類(lèi)進(jìn)行修改, 而不會(huì)造成破壞.例如假設(shè)這個(gè)組織的市場(chǎng)部決定,除了現(xiàn)有的部門(mén)外, 他們還需要一個(gè)特殊的在線(xiàn)市場(chǎng)部,. 這樣一來(lái), switch/case操作需要一個(gè)新的分支(case), 還要有一個(gè)新的私有屬性(變量)來(lái)描述新增的這個(gè)部門(mén).這個(gè)改變將封凍在單獨(dú)的類(lèi)中, 而不會(huì)影響其他參與者.由于這種改變不會(huì)帶來(lái)破壞, 所以應(yīng)用的規(guī)模越大, 這一點(diǎn)就越重要.可以看到原型設(shè)計(jì)模式不僅支持一致性, 還支持靈活的改變.

PHP世界中的原型

由于PHP是一個(gè)服務(wù)器端語(yǔ)言,也是與MySQL數(shù)據(jù)庫(kù)交互的一個(gè)重要工具,所以原型設(shè)計(jì)模式尤其適用 .并不是為數(shù)據(jù)庫(kù)的第一個(gè)元素分別創(chuàng)建對(duì)象,PHP可以使用原型模式創(chuàng)建具體類(lèi)的一個(gè)實(shí)例,然后利用數(shù)據(jù)庫(kù)中的數(shù)據(jù)克隆其余的實(shí)例(記錄).

了解克隆過(guò)程之后,與直接實(shí)例化的過(guò)程相比,你可能會(huì)問(wèn):"這有什么區(qū)別?" 換句話(huà)說(shuō),為什么克隆比直接實(shí)例化對(duì)象需要的資源少?它們的區(qū)別并不能直接看到. 一個(gè)對(duì)象通過(guò)克隆創(chuàng)建實(shí)例時(shí), 它不會(huì)啟動(dòng)構(gòu)造函數(shù).克隆能得到原始類(lèi)的所有屬性, 甚至還包含父接口的屬性,另外還繼承了傳遞實(shí)例化對(duì)象的所有值.構(gòu)造函數(shù)生成的所有值以及存儲(chǔ)在對(duì)象屬性中的值都會(huì)成為克隆對(duì)象的一部分.所以沒(méi)有返回構(gòu)造函數(shù).如果發(fā)現(xiàn)你的克隆對(duì)象確實(shí)需要訪(fǎng)問(wèn)構(gòu)造函數(shù)生成的值但又無(wú)法訪(fǎng)問(wèn), 這說(shuō)明需要對(duì)類(lèi)進(jìn)行重構(gòu),使實(shí)例能擁有它們需要的一切信息, 而且可以把這些數(shù)據(jù)傳遞給克隆對(duì)象.

總的來(lái)說(shuō), 原型模式在很多不同類(lèi)型的PHP項(xiàng)目中都很適用, 如果解決一個(gè)問(wèn)題需要乃至創(chuàng)建型模式, 都可以使用原型模式.

以上是“PHP設(shè)計(jì)模式之原型模式的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

php
AI