您好,登錄后才能下訂單哦!
這篇文章主要介紹PHP設計模式之原型模式的示例分析,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!
本文實例講述了PHP設計模式之原型模式定義與用法。分享給大家供大家參考,具體如下:
原型設計模式(Prototype Design Pattern)很有意思, 因為它使用了一種克隆技術來復制實例化的對象. 新對象是通過復制原型實例來創建的. 在這里, 實例是批實例化的具體類.原型設計模式的目的是通過使用克隆來減少實例化對象的開銷.與其從一個類實例化新對象, 完全可以使用一個已有實例的克隆.
克隆函數
PHP中使用原型設計模式的關鍵是要了解如何使用內置函數__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();
運行結果如下
look : handsome
chenqionghe
look : still handsome
chenqionghe
$cloneBoy實例是通過克隆Boy的實例$boy, 它可以像$boy一樣訪問相同的屬性, 而且像Boy類的直接實例一樣改變這些屬性.
注意: 對于所克隆的實例 , clone關鍵字會為該實例的類實例化另一個實例(使用克隆關鍵字可以創建一個類的副本, 如果可能, 會自動調用對象的__clone
方法, 但不能直接調用 對象的__clone
方法), 關于過程, 有一點需要注意的是, 克隆不會不會啟動構造函數中的動作.
簡單的原型例子
我們以研究果蠅為例.研究的目標是建立一個原型果蠅, 然后一旦出現變異, 就構建這個變異果蠅
抽象類接口和具體實現
原型(IPrototype)的兩個具體類實現分別表示不同性別的果蠅, 包括性別變量(gender)和不同性別的和行為.
IPrototype.php
<?php abstract class IPrototype { public $eyeColor; public $winBeat; public $unitEypes; abstract function __clone(); }
IPrototype的這兩個實現的區別體現在性別上, 性別用常量標識, 一個是MALE,另一個是FEMAIL.雄果蠅有一個$mated布爾變量, 雄果蠅交配后,這個布爾變量會設置為true, 雌果蠅有一個$fecundity變量,其中包含一個數字值, 表示這只雄果蠅的繁殖能力(產卵個數):
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(){} }
客戶
在原型設計模式中,Clien類確實是一個不可缺少的部分.原因在于, 盡管要將子類具體實現作為實例的模板,但使用相同的模板克隆實例的具體工作是由Client類完成的
Client.php
<?php function __autoload($class_name) { include_once $class_name.'.php'; } class Client { //用于直接實例化 private $fly1; private $fly2; //用于克隆 private $c1Fly; private $c2Fly; private $updatedCloneFly; public function __construct() { //實例化 $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'; //通過類型提示方法發送 $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();
運行結果如下
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
原型模式要依賴客戶通過 不念克隆過程使用具體原型.在這個設計過程中, 客戶是完成克隆的參與者, 由于克隆是原型設計中的關鍵要素, 所以客戶是一個基本參與者, 而不僅僅是一個請求類.
現代企業組織
在創建型設計模式方面,現代企業組織就非常適合原型實現.現在企業組織往往是復雜而龐大的層次結構, 像面向對象編程一樣,要為很多共同的特征建模.現在通過一個例子描述軟件工程公司.
軟件工程公司是一個典型的現代組織.工程部(Engineering Department)負責創建產品,管理部(Management)處理資源的協調組織,市場部(Marketing)負責產品的銷售,推廣和整體營銷.
接口中的封裝
在這個原型實現中,首先為程序的接口(一個抽象類)增加OOP,與所有原型接口一樣,這個接口包含一個克隆操作.另外它還包含一些抽象和具體的獲取方法和設置方法.其中有一個抽象獲取方法/設置方法對,但要由3個具體原型實現為這個抽象獲取方法/設置方法對提供具體實現.其他獲取方法和設置方法分分別應用于員工名,ID碼和照片等屬性.注意所有這些屬性都是保護屬性(protected),所以盡管具體的獲取方法和設置方法有公共可見性,但由于操作中使用的屬性具有保護和可見性,這就提供了某種程度的封裝:
<?php abstract class IAcmePrototype { protected $name; protected $id; protected $employeePic; protected $department; //部門 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(); }
利用這些獲取方法和設置方法, 所有屬性的值都通過繼承的保護變量來設置.采用這種設計, 擴展類及其實例可以得到更好的封裝.
接口實現
3個IAcmePrototype子類都必須實現"dept"抽象方法以及__clone()
方法.類似地, 每個具體原型類還包含一個常量UNIT,它提供一個賦值,可以由實例(包括克隆的對象)作為標識
首先來看市場部的Marketing類:
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 = "未識別的市場部"; } } public function getDept() { return $this->department; } public function __clone() {} }
setDept()
方法的實現使用了一個參數.并不是直接輸入市場部的部門,這個方法的參數是一個數字碼, 通過一個switch語句,限制了3種可接受的情況和默認情況,別外兩個原型實現也類似
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 = "未識別的管理部"; } } 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 = "未識別的工程部"; } } public function getDept() { return $this->department; } public function __clone() {} }
以上這3個具體原型實現分別有其特定用途,不過它們都符合接口,可以創建各個原型實現的一個實例, 然后根據需要克隆多個實例.這個克隆的工作由Client類完成
客戶
客戶的設置非常簡單: 分別創建各個具體原型的一個實例, 然后按以下列表來克隆各個實例:
市場部門實例:
-----市場部門克隆
-----市場部門克隆
管理部門實例
-----管理部門克隆
工程部門實例
-----工程部門克隆
-----工程部門克隆
將來只使用這些克隆對象.使用獲取方法和設置方法將各個特定情況的信息賦給這些克隆對象.以下是Client的實現
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();
解釋:
客戶Client的構造函數類包含3個私有屬性, 用來分別實例化3個具體原型類. makeConPro()
方法生成必要的實例.
接下來,使用克隆技術創建一個"員工"實例.然后,這個實例向一個設置方法setEmployee()發送特定的實例信息,這個設置方法使用IAcmePrototype接口類型提示,不過需要說明, 它只對第一個參數使用類型提示,其他參數都沒有類型提示, 并不要求它們派生自IAcmePrototype接口.克隆"員工"可以使用IAcmePrototype抽象類的所有設置方法以及具體原型類實現的setDept()方法.
要使用各個員工的數據,Client類可以使用繼承的獲取方法.以下是運行Client輸出的結果
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
未識別的工程部:Engineering
jj301-14548
可以根據需要增加更多的克隆, 而且只需要對具體原型類完成一次實例化.使用原型模式時, 并不是建立具體類的多個實例,而只需要一個類實例化和多個克隆.
完成修改,增加特性
要記住,最重要(可能也是最基本)的是, 設計模式允許開發人員修改和增補程序,而不必一切從頭開始.例如, 假設總裁決定公司增加一個新的部門,比如研究部門(Research), 這會很難嗎?一點也不難.Research可以擴展IAcmePrototype抽象類, 然后實現抽象獲取方法和設置方法來反映這個研究部門的組織.需要說明,Client類中獲取方法和設置方法使用的代碼提示指示一個接口,而不是一個抽象類的具體實現.所以, 只要增加的單元正確地實現了這個接口,就能順利地增加到應用中, 而不會帶來波動,也不需要對程序中的其他參與者進行重構.
不僅可以增加更多的具體類, 還可以很容易地對各個類進行修改, 而不會造成破壞.例如假設這個組織的市場部決定,除了現有的部門外, 他們還需要一個特殊的在線市場部,. 這樣一來, switch/case操作需要一個新的分支(case), 還要有一個新的私有屬性(變量)來描述新增的這個部門.這個改變將封凍在單獨的類中, 而不會影響其他參與者.由于這種改變不會帶來破壞, 所以應用的規模越大, 這一點就越重要.可以看到原型設計模式不僅支持一致性, 還支持靈活的改變.
PHP世界中的原型
由于PHP是一個服務器端語言,也是與MySQL數據庫交互的一個重要工具,所以原型設計模式尤其適用 .并不是為數據庫的第一個元素分別創建對象,PHP可以使用原型模式創建具體類的一個實例,然后利用數據庫中的數據克隆其余的實例(記錄).
了解克隆過程之后,與直接實例化的過程相比,你可能會問:"這有什么區別?" 換句話說,為什么克隆比直接實例化對象需要的資源少?它們的區別并不能直接看到. 一個對象通過克隆創建實例時, 它不會啟動構造函數.克隆能得到原始類的所有屬性, 甚至還包含父接口的屬性,另外還繼承了傳遞實例化對象的所有值.構造函數生成的所有值以及存儲在對象屬性中的值都會成為克隆對象的一部分.所以沒有返回構造函數.如果發現你的克隆對象確實需要訪問構造函數生成的值但又無法訪問, 這說明需要對類進行重構,使實例能擁有它們需要的一切信息, 而且可以把這些數據傳遞給克隆對象.
總的來說, 原型模式在很多不同類型的PHP項目中都很適用, 如果解決一個問題需要乃至創建型模式, 都可以使用原型模式.
以上是“PHP設計模式之原型模式的示例分析”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。