天天看點

設計模式(四)原型模式Prototype(建立型) 設計模式(四)原型模式Prototype  1.   概述 3. 解決方案 4. 适用性 5. 結構 6. 組成

我們都知道,建立型模式一般是用來建立一個新的對象,然後我們使用這個對象完成一些對象的操作,我們通過原型模式可以快速的建立一個對象而不需要提供專門的new()操作就可以快速完成對象的建立,這無疑是一種非常有效的方式,快速的建立一個新的對象。 例子1:孫悟空拔下一嘬猴毛,輕輕一吹就會變出好多的孫悟空來。 例子2:寄個快遞 下面是一個郵寄快遞的場景: “給我寄個快遞。”顧客說。 “寄往什麼地方?寄給……?”你問。 “和上次差不多一樣,隻是郵寄給另外一個位址,這裡是郵寄位址……”顧客一邊說一邊把寫有郵寄位址的紙條給你。 “好!”你愉快地答應,因為你儲存了使用者的以前郵寄資訊,隻要複制這些資料,然後通過簡單的修改就可以快速地建立新的快遞資料了。

       通過複制(克隆、拷貝)一個指定類型的對象來建立更多同類型的對象。這個指定的對象可被稱為“原型”對象,也就是通過複制原型對象來得到更多同類型的對象。即原型設計模式。在php的很多模闆庫,都用到clone。如smarty等。

原型模式的主要思想是基于現有的對象克隆一個新的對象出來,一般是有對象的内部提供克隆的方法,通過該方法傳回一個對象的副本,這種建立對象的方式,相比我們之前說的幾類建立型模式還是有差別的,之前的講述的工廠模式與抽象工廠都是通過工廠封裝具體的new操作的過程,傳回一個新的對象,有的時候我們通過這樣的建立工廠建立對象不值得,特别是以下的幾個場景的時候,可能使用原型模式更簡單也效率更高。 • 1)當一個系統應該獨立于它的産品建立、構成和表示時,要使用 prototype模式 • 2)當要執行個體化的類是在運作時刻指定時,例如,通過動态裝載; • 3)為了避免建立一個與産品類層次平行的工廠類層次時 • 4)當一個類的執行個體隻能有幾個不同狀态組合中的一種時。建立相應數目的原型并克隆它們可能比每次用合适的狀态手工執行個體化該類更友善一些。(也就是當我們在處理一些對象比較簡單,并且對象之間的差別很小,可能隻是很固定的幾個屬性不同的時候,可能我們使用原型模式更合适)。

     原型模式結構如下頁上圖所示:

設計模式(四)原型模式Prototype(建立型) 設計模式(四)原型模式Prototype  1.   概述 3. 解決方案 4. 适用性 5. 結構 6. 組成

7. 效果

prototype模式有許多和abstract factory模式 和 builder模式一樣的效果:它對客戶隐藏了具體的産品類,是以減少了客戶知道的名字的數目。此外,這些模式使客戶無需改變即可使用與特定應用相關的類。 下面列出prototype模式的另外一些優點。 1 ) 運作時刻增加和删除産品: prototype允許隻通過客戶注冊原型執行個體就可以将一個新的具體産品類并入系統。它比其他建立型模式更為靈活,因為客戶可以在運作時刻建立和删除原型。 2 ) 改變值以指定新對象: 高度動态的系統允許你通過對象複合定義新的行為—例如,通過為一個對象變量指定值—并且不定義新的類。你通過執行個體化已有類并且将這些執行個體注冊為客戶對象的原型,就可以有效定義新類别的對象。客戶可以将職責代理給原型,進而表現出新的行為。這種設計使得使用者無需程式設計即可定義新“類” 。實際上,克隆一個原型類似于執行個體化一個類。prototype模式可以極大的減少系統所需要的類的數目。 3) 改變結構以指定新對象:許多應用由部件和子部件來建立對象。 4) 減少子類的構造 factory method 經常産生一個與産品類層次平行的 creator類層次。prototype模式使得你克隆一個原型而不是請求一個工廠方法去産生一個新的對象。是以你根本不需要creator類層次。這一優點主要适用于像 c + +這樣不将類作為一級類對象的語言。像smalltalk和objective c這樣的語言從中獲益較少,因為你總是可以用一個類對象作為生成者。在這些語言中,類對象已經起到原型一樣的作用了。 5) 用類動态配置應用 一些運作時刻環境允許你動态将類裝載到應用中。在像 c + +這樣的語言中,prototype模式是利用這種功能的關鍵。一個希望建立動态載入類的執行個體的應用不能靜态引用類的構造器。而應該由運作環境在載入時自動建立每個類的執行個體,并用原型管理器來注冊這個執行個體(參見實作一節) 。這樣應用就可以向原型管理器請求新裝載的類的執行個體,這些類原本并沒有和程式相連接配接。 e t + +應用架構[ w g m 8 8 ]有一個運作系統就是使用這一方案的。 prototype的主要缺陷是每一個prototype的子類都必須實作clone操作,這可能很困難。 例如,當所考慮的類已經存在時就難以新增 clone操作。當内部包括一些不支援拷貝或有循環引用的對象時,實作克隆可能也會很困難的。

8. 實作

<?php  

/** 

 * 原型模式  

 */  

 * 抽象原型角色 

interface prototype {  

    public function copy();  

}  

 * 具體原型角色 

class concreteprototype implements prototype{  

    private  $_name;  

    public function __construct($name) {  

        $this->_name = $name;  

    }  

    public function setname($name) {  

    public function getname() {  

        return $this->_name;  

    public function copy() {  

       /** 深拷貝 */  

       return  clone  $this;      

       /** 淺拷貝 */  

       //return  $this;     

class client {  

     /** 

     * main program. 

     */  

    public static function main() {  

        $object1 = new concreteprototype(11);  

        $object_copy = $object1->copy();  

        var_dump($object1->getname());  

        echo '<br />';  

        var_dump($object_copy->getname());  

        $object1->setname(22);  

client::main();  

?>  

9. 淺拷貝和深拷貝

設計模式(四)原型模式Prototype(建立型) 設計模式(四)原型模式Prototype  1.   概述 3. 解決方案 4. 适用性 5. 結構 6. 組成

10. 帶prototype manager的原型模式

     原型模式的第二種形式是帶原型管理器的原型模式,其uml圖如下:

設計模式(四)原型模式Prototype(建立型) 設計模式(四)原型模式Prototype  1.   概述 3. 解決方案 4. 适用性 5. 結構 6. 組成

       原型管理器(prototype manager)角色:建立具體原型類的對象,并記錄每一個被建立的對象。

       下面這個例子示範了在原型管理器中存儲使用者預先定義的顔色原型,客戶通過原型管理器克隆顔色對象。

 * abstract prototype 

 * 

abstract class colorprototype  

{  

  //methods  

    abstract function  copy();  

 * concrete prototype 

class color extends colorprototype{  

    //fields  

    private  $red;  

    private  $green;  

    private  $blue;  

    //constructors  

    function __construct( $red, $green, $red) {  

        $this->red = $red;  

        $this->green = $green;  

        $this->blue = $red;  

     }  

      * set red 

      * 

      * @param unknown_type $red 

      */  

    public  function setred($red) {  

      * get red 

    public  function getred(){  

        return  $this->red;  

      *set green 

      * @param  $green 

    public  function setgreen($green) {  

      * get green 

      * @return unknown 

    public  function getgreen() {  

        return  $this->green ;  

      *set blue 

      * @param  $blue 

    public  function setblue($blue) {  

        $this->blue = $blue;  

      * get blue 

    public  function getblue() {  

        return  $this->blue ;  

    /** 

     * enter description here... 

     * 

     * @return unknown 

    function copy(){  

        return clone $this;  

    function display() {  

        echo $this->red , ',', $this->green, ',', $this->blue ,'<br>';  

 * enter description here... 

class colormanager  

    // fields  

    static  $colors = array();  

    // indexers  

    public static function add($name, $value){  

        self::$colors[$name] = $value;  

    public static function getcopy($name) {  

        return   self::$colors[$name]->copy();  

 *client 

class client  

    public static function  main()  

    {  

        //原型:白色  

        colormanager::add("white", new color( 255, 0, 0 ));  

        //紅色可以由原型白色對象得到,隻是重新修改白色: r  

        $red = colormanager::getcopy('white');  

        $red->setred(255);  

        $red->display();  

        //綠色可以由原型白色對象得到,隻是重新修改白色: g  

        $green = colormanager::getcopy('white');  

        $green->setgreen(255);  

        $green->display();  

        //綠色可以由原型白色對象得到,隻是重新修改白色: b  

        $blue = colormanager::getcopy('white');  

        $blue->setblue(255);  

        $blue->display();  

ini_set('display_errors', 'on');  

error_reporting(e_all & ~ e_deprecated);